Robitex's Blog

Ideas in the web

Ottenere il PDF di un post di WordPress


Sarebbe utile se…

…ci fosse una maniera semplice e veloce per mettere a disposizione degli utenti del blog il file dell’articolo anche in formato PDF pronto per la stampa!

Che dire, con Lua questo ed altro!

Doverosa premessa

Il problema di convertire il testo tra formati diversi dovrebbe essere già risolto con i tool esistenti. In realtà non è proprio così semplice perché i due formati possono differire semanticamente.

Per esempio se il formato di partenza è html, e si vuol produrre il PDF con LaTeX per assicurarsi la massima qualità tipografica, allora alcune strutture possono non avere un diretto equivalente. Se poi nel sorgente html vi sono alcuni tag propri di WordPress come quelli per il codice che funzionano con Javascript le cose sono di difficile generalizzazione.

Codice

Con i tag specifici di WordPress e con le specifiche che di solito utilizzo, ho risolto scrivendo uno script in Lua che legge il file html, converte i tag in costrutti LaTeX, crea il file sorgente su disco ed infine lo compila con pdfLaTeX, con tanto di sommario cliccabile.

Uniche note di spiegazione che do del codice è l’uso massiccio della funzione string.gsub(), spesso in modo semplice, alcune volte invece con l’uso di funzioni anonime di sottoformattazione come il caso delle formule matematiche (renderizzate da WordPress con LaTeX stesso), e nel caso di inserimento di immagini.

#!/usr/bin/lua

-- 2010 12 15
-- trasforma un file di WordPress dal formato html
-- al formato pdf attraverso LaTeX
--
-----------------------
-- functions section --
-----------------------
local function readFile( fn )
    local f = assert(io.open(fn , "r"))
    return f:read("*all")
end

local function getFilename( s )
   if not string.find(s, "%.") then
       return s
   else
      return string.match(s, "(.*)%.[^%.]-$")
   end
end

local function html2latex( s )
     local result = string.gsub(s, "%[sourcecode%]", "\\begin{lstlisting}")
     result = string.gsub(result, "%[/sourcecode%]", "\\end{lstlisting}")
     result = string.gsub(result, "<h4>(.-)</h4>", "\\subsection{%1}")
     result = string.gsub(result, "<h3>(.-)</h3>", "\\section{%1}")
     result = string.gsub(result, "<h2>(.-)</h2>", "\\section{%1}")
     result = string.gsub(result, "<strong>(.-)</strong>",
                 function (s)
                     return "\\textbf{" .. string.gsub(s, "_" , "\\_") .."}"
                 end
                 )
     result = string.gsub(result, "<em>(.-)</em>", "\\emph{%1}")
     result = string.gsub(result, "%$latex%s+(.-)%$",
                function (s)
                    local s1 = string.match(s,"^\\displaystyle(.*)")
                    if s1 then
                        return "\\[\n" .. s1 .."\n\\]"
                    else
                        return "\\(" .. s .. "\\)"
                    end
                end
               )
     
     -- url substitution     
     result = string.gsub(result,
                          "<a%s+href%s*=%s*[\'\"](.-)[\'\"]>(.-)</a>",
                          "\\href{%1}{%2}")
     result = string.gsub(result,
              "%[caption%s+.-caption%s*=%s*[\'\"](.-)[\'\"].-src%s*=%s*[\'\"](.-)[\'\"].-%/caption%]",
              function (cp,uurrll) return "\\begin{figure}\n\\centering\n"..
                                          "\\includegraphics{" .. string.match(uurrll, "[^/]-$") .. }\n" ..
                                          "\\caption{"..cp.."}\n\\end{figure}\n" end
                                          )
     return result
end

-- create the LaTeX source file
local function makeSource( fn , s )
    -- apertura file
    local f = assert(io.open( fn  .. ".tex", "w"))
    -- scrittura dati
   f:write(s)
   -- chiusura del file
   f:close()
end
-- compile file by name without extension
local function makePDF( fn )
      print("Start pdfLaTeX twin runs...")
      os.execute("pdflatex " .. fn)
       os.execute("pdflatex " .. fn)
       os.remove(fn..".log")
       os.remove(fn..".aux")
       print("End")
end
------------------------------
-- constant strings section --
------------------------------

local preambleDoc = [[
\documentclass[a4paper,10pt]{article}

\usepackage[utf8]{inputenc}
\usepackage[italian]{babel}
\usepackage[T1]{fontenc}
\usepackage[margin=18mm]{geometry}
\usepackage{indentfirst}
\usepackage{microtype}

\usepackage{listings}
\usepackage{xcolor}
\usepackage{inconsolata}
\usepackage{graphicx}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}

\lstset{%
   backgroundcolor=\color{yellow!20},
   basicstyle=\small\ttfamily,
   framexleftmargin=5pt
}
]]

local openingDoc = [[
% opening
\title{}
\author{The Blogger\\blogger dot email dot mailbox at ecc dot com}
]]

local startDoc = [[
\begin{document}

\maketitle

\begin{abstract}
Articolo dal blog di WordPress
\end{abstract}

\vfill
\tableofcontents
\vfill

\newpage
]]

local endDoc = [[
\end{document}
]]

--------------------------
-- main execution chunk --
--------------------------
local filename = arg[1]

if not filename then
    print("Errore: file d'ingresso non specificato come argomento")
    os.exit()
end

local fname = getFilename(filename)

local contentLaTeX = {}
contentLaTeX[#contentLaTeX+1] = preambleDoc
contentLaTeX[#contentLaTeX+1] = openingDoc
contentLaTeX[#contentLaTeX+1] = startDoc
contentLaTeX[#contentLaTeX+1] = html2latex( readFile( filename ))
contentLaTeX[#contentLaTeX+1] = endDoc

makeSource( fname , table.concat(contentLaTeX) )
makePDF( fname )

-- end of file

Come è ovvio il sorgente LaTeX viene mantenuto nella stessa directory del file html per consentire di effettuare degli aggiustamenti di finezza che solo gli utenti LaTeX sanno percepire🙂

Bè le ciambelle non sempre vengono col buco… e per applicare lo script a questo stesso articolo ho dovuto intervenire manualmente perché il codice sostituisce anche i tag nel sorgente Lua (cosa da non fare evidentemente).

Poiché capiterà solo per questo post, non correggerò lo script lasciando a voi di proporre la giusta patch.
Scarica questo post nel formato PDF ottenuto con lo script descritto in questo stesso post.
Ciao ed alla prossima.

2 risposte a “Ottenere il PDF di un post di WordPress

  1. luca 05/02/2011 alle 19:28

    Perdona l’ignoranza, ma come faccio a lanciare lo script dalla pagina dell’ articlo? So che devo modificare il file single.php aggiungendo magari un’icona… ma che riferimento gli devo dare?
    Complimenti per lo script.

    • robitex 06/02/2011 alle 11:46

      Ciao Luca,
      lo script Lua lavora in “locale” ed hai ragione, nel post non l’ho ben spiegato.
      Il contesto è questo: il blog è ospitato dai server WordPress per cui non è possibile intervenire sulla struttura predefinita ma semplicemente fare l’upload del pdf dell’articolo ed inserire nell’articolo stesso il link per il download.
      Siamo per così dire in condizioni statiche, nella quale il pdf non viene creato al volo, ma è un normalissimo file di cui è possibile eseguire il download.
      La sequenza di lavoro è:
      1- copiare in un file di testo in locale il codice html del post dalla pagina amministrativa di WP;
      2- eseguire lo script sul file;
      3- operare eventuali correzioni al sorgente tex o allo script stesso;
      4- pubblicare l’aggiornamento del post con in alto il link al pdf così ottenuto.

      La procedura “on the fly” avrebbe il vantaggio di produrre sempre il pdf dell’articolo aggiornato, mentre nel mio caso, se sussistono modifiche all’articolo, occorre rigenerare e sostituire il file pdf (doppia modifica) dal pannello admin, ma non sarebbe possibile eseguire modifiche manuali al sorgente tex e ciò comporterebbe un aggravio di regole sintattiche nella scrittura del codice html per farlo aderire ai casi previsti dallo script.
      Script che potrebbe essere di gran lunga migliorato rispetto a quello pubblicato nel post, utilizzando una struttura ad albero proprio come si farebbe con i nodi xml, e non è escluso che tale versione non possa vedere un giorno la luce…
      R.

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: