Jakiś czas temu leaderzy projektu opensolaris-pl podjęli decyzję o wzięciu się za tłumaczenie uwolnionych książek Suna. Na pierwszy ogień poszedł Solaris ZFS Administration Guide. Prace nad tłumaczeniem ZFSADMIN powoli posuwają się naprzód, niedługo prawdopodobnie będzie potrzeba przerabiania tych “nieszczęsnych” plików XML (Sun opublikował swoje książki w formacie DocBook 5 XML) do bardziej czytelnej formy dla przeciętnego użytkownika. Po straceniu całego dnia na zrozumienie, jak to właściwie działa, wkurzaniu się, czemu nie działa tak, jakbym ja sobie wymarzył, przeczytaniu prawie całego DocBook XSL: The Complete Guide (swoją drogą polecam – świetna książka) jestem gotów zaprezentować sposób przygotowania sobie środowiska do generowania ebooków w postaci HTML i PDF.
Uwagi:
- Jeśli chodzi o system operacyjny, opis bazuje na przykładzie Debian Unstable – akurat tego środowiska używałem w danym momencie;
- Poniżej podaję przykładowe konfiguracje programów, które działają u mnie – nie gwarantuję, że zadziałają też u Ciebie ;)
- Jeśli dostrzegłeś jakieś błędy, napisałem coś błędnie, chcesz dostarczyć informacji, jak to wygląda pod innym systemem – Jestem otwarty na krytykę
Co potrzebujemy?
W zależności od potrzeb:
- Obowiązkowo musimy posiadać (wystarczy to do konwersji dokumentów na HTML, XHTML, XSL-FO – ten ostatni jest etapem przejściowym do konwersji na PDF):
- Bibliotekę libxslt;
- Procesor XSLT, czyli xsltproc (jest składnikiem libxslt);
- Arkusze stylów DocBook, najlepiej wersja z przestrzeniami nazw (tę wersję wykorzystuje uwolniona dokumentacja Suna, wersja bez przestrzeni nazw też będzie działać, tylko sypie “warningami”;
- Jeśli zależy nam na konwersji do formatu PDF, to oprócz tego musimy jeszcze doinstalować:
- Procesor do konwersji XSL-FO na PDF – w naszym przypadku darmowy fop, większość takich procesorów jest komercyjna;
- Biblioteka dla fop zawierająca reguły informujące o sposobie podziału wyrazów na sylaby (fop-hyph) do ściągnięcia tutaj (wersja stable);
- Czcionki z polskimi znakami – domyślnie FOP korzysta z zestawu bazowych 14 czcionek Adobe (Helvetica, Times, Courier, każdy w wersji Normal, Italic, Bold, Bold Italic, oraz jeszcze czcionki Symbol i ZapfDingbats). Niestety czcionki te nie mają polskich znaków, więc w naszym przypadku musimy załączyć odpowiednie fonty bezpośrednio do PDF-a. Osobiście wykorzystałem czcionki TrueType Microsoftu: Verdana, Times New Roman, Courier New.
W większości dystrybucji elementy te są dostępne w paczkach z określonymi zależnościami. W Debianie sprowadza się to do:
# apt-get install xsltproc fop msttcorefonts
W repozytorium znajduje się także wersja arkuszy stylów DocBook (pakiet docbook-xsl), ale jest to wersja bez przestrzeni nazw (namespace). W związku z tym ściągamy tę wersję bezpośrednio z podanej wyżej strony (ostatnia wersja: docbook-xsl-ns-1.73.0) i rozpakowujemy w wygodnym nam miejscu (w moim przypadku /opt/share/xml/docbook/).
Wróćmy jeszcze do konfiguracji FOP. Domyślnie jest on wywoływany przez skrypt-wrapper /usr/bin/fop, który ma mały błąd – usiłuje traktować konfigurację jako skrypt shellowy – proponuję nałożenie tego patcha
Jeśli zamierzamy korzystać z biblioteki fop-hyph.jar, trzeba wskazać programowi jej lokalizację. Robimy to przez ustawienie zmiennej FOP_HYPHENATION_PATH.
Ponieważ będziemy potrzebować czcionki z polskimi literami, musimy wygenerować sobie tzw. metryki tych czcionek, po czym wskazać w konfiguracji fopa, pod jakimi nazwami będą one widoczne. Jako, że nie bardzo mamy ochotę zmieniać rodziny czcionek w całej dokumentacji Suna, zdecydowałem się na podmianę domyślnych fontów klasy serif, sans-serif i monospace odpowiednio na Times New Roman, Verdana i Courier New. Metryki umieściłem w katalogu /etc/fop/, generuje się je z plików TTF w następujący sposób:
# fop-ttfreader /usr/share/fonts/truetype/msttcorefonts/times.ttf /etc/fop/serif.xml
Analogicznie trzeba wygenerować metryki dla pozostałych czcionek i ich wersji (italic, bold, bold italic).
Następnie potrzebujemy jeszcze konfiguracji fopa z uwzględnieniem czcionek – przykładowa, prawie minimalna zawartość pliku /etc/fop.conf:
<?xml version="1.0"?>
<fop version="1.0">
<base>.</base>
<source-resolution>72</source-resolution>
<target-resolution>72</target-resolution>
<default-page-settings height="297mm" width="210mm"/>
<renderers>
<renderer mime="application/pdf">
<filterList>
<value>flate</value>
</filterList>
<fonts>
<font metrics-url="/etc/fop/sans-serif.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/verdana.ttf">
<font-triplet name="sans-serif" style="normal" weight="normal"/>
</font>
<font metrics-url="/etc/fop/sans-serifi.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/verdanai.ttf">
<font-triplet name="sans-serif" style="italic" weight="normal"/>
</font>
<font metrics-url="/etc/fop/sans-serifb.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/verdanab.ttf">
<font-triplet name="sans-serif" style="normal" weight="bold"/>
</font>
<font metrics-url="/etc/fop/sans-serifbi.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/verdanaz.ttf">
<font-triplet name="sans-serif" style="italic" weight="bold"/>
</font>
<font metrics-url="/etc/fop/serif.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/times.ttf">
<font-triplet name="serif" style="normal" weight="normal"/>
</font>
<font metrics-url="/etc/fop/serifi.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/timesi.ttf">
<font-triplet name="serif" style="italic" weight="normal"/>
</font>
<font metrics-url="/etc/fop/serifb.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/timesbd.ttf">
<font-triplet name="serif" style="normal" weight="bold"/>
</font>
<font metrics-url="/etc/fop/serifbi.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/timesbi.ttf">
<font-triplet name="serif" style="italic" weight="bold"/>
</font>
<font metrics-url="/etc/fop/monospace.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/cour.ttf">
<font-triplet name="monospace" style="normal" weight="normal"/>
</font>
<font metrics-url="/etc/fop/monospacei.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/couri.ttf">
<font-triplet name="monospace" style="italic" weight="normal"/>
</font>
<font metrics-url="/etc/fop/monospaceb.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/courbd.ttf">
<font-triplet name="monospace" style="normal" weight="bold"/>
</font>
<font metrics-url="/etc/fop/monospacebi.xml" kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/courbi.ttf">
<font-triplet name="monospace" style="italic" weight="bold"/>
</font>
</fonts>
</renderer>
<renderer mime="application/postscript">
</renderer>
<renderer mime="application/vnd.hp-PCL">
</renderer>
<renderer mime="image/svg+xml">
<format type="paginated"/>
<link value="true"/>
<strokeText value="false"/>
</renderer>
<renderer mime="application/awt">
</renderer>
<renderer mime="image/png">
</renderer>
<renderer mime="image/tiff">
</renderer>
<renderer mime="text/xml">
</renderer>
<renderer mime="text/plain">
<pageSize columns="80"/>
</renderer>
</renderers>
</fop>
Taka konfiguracja programu fop powinna nam zapewnić poprawne generowanie plików PDF z polskimi znakami.
Jak uzyskać z tego teraz książkę w formacie HTML?
Konwersja składa się z kilku etapów. Na początku dla każdej docbooka trzeba zbudować bazę odnośników, którą procesor później wykorzystuje do tworzenia prawidłowych linków pomiędzy w książce. Proces ten jest konieczny z racji rozbicia książki na pojedyncze pliki XML, w związku z czym procesor musi najpierw sobie stworzyć bazę, w którym pliku jakie identyfikatory odnośników występują. Robimy to wchodząc do katalogu książki i wydając polecenie:
$ xsltproc --xinclude \\
--stringparam collect.xref.targets "only" \\
/opt/share/xml/docbook/docbook-xsl-ns-1.73.0/html/chunk.xsl \\
ZFSADMIN.xml
Wyjaśnienie parametrów:
- --xinclude – wymusza przetwarzanie dokumentów z użyciem specyfikacji XInclude. Cała dokumentacja Suna korzysta z tego rozszerzenia;
- --stringparam collect.xref.targets “only” – stringparam w ogólności służy do przekazywania parametrów do arkuszy stylów – parametr collect.xref.targets odpowiedzialny jest za zachowanie przy natrafieniu na linki. Argument only określa, że chcemy tylko zebrać informację o linkach;
- /opt/share/xml/docbook/docbook-xsl-ns-1.73.0/html/chunk.xsl – ścieżka do arkusza stylów – wykorzystujemy chunk.xsl, żeby wygenerować dokumentację w formie kilkunastu podzielonych sensownie plików HTML (na przykład każdy rozdział w osobnym pliku HTML), zamiast jednego dużego (który uzyskamy po zastosowaniu docbook.xsl);
- ZFSADMIN.xml – ścieżka do “początku” dokumentu;
W wyniku działania powyższego polecenia uzyskamy plik target.db.
Następnie musimy posiadać plik XML opisujący listę “celów” powiązanych z bazą odnośników. W przypadku pojedynczej książki przykładowy plik wygląda tak (zapisałem go pod nazwą olinkbase.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE targetset
SYSTEM "file:///opt/share/xml/docbook/docbook-xsl-ns-1.73.0/common/targetdatabase.dtd" [
<!ENTITY zfsadmintarget SYSTEM "file:///home/dosiu/docbook/ZFSADMIN/target.db">
]>
<targetset>
<sitemap>
<dir name="html">
<document targetdoc="ZFSADMIN">
&zfsadmintarget;
</document>
</dir>
</sitemap>
</targetset>
Składnia pliku dość dobrze jest opisana w DocBook XSL: The Complete Guide (konkretnie tutaj), więc nie będę się dublować.
Mając to, możemy spróbować wygenerować plik HTML:
$ xsltproc --xinclude \\
--stringparam chunker.output.doctype-public "-//W3C//DTD HTML 4.01 Transitional//EN" \\
--stringparam chunker.output.doctype-system "http://www.w3.org/TR/html4/loose.dtd" \\
--stringparam chunker.output.encoding UTF-8 \\
--stringparam target.database.document "olinkbase.xml" \\
--stringparam current.docid "ZFSADMIN" \\
-o html/index.html \\
/opt/share/xml/docbook/docbook-xsl-ns-1.73.0/html/chunk.xsl \\
ZFSADMIN.xml
Z przekazywanych parametrów dość ważne jest chunker.output.encoding – domyślnie pliki HTML generowane są z użyciem kodowania ISO-8859-1. Podanie tego parametru wymusza użycie wskazanego kodowania. chunker.output.doctype-public oraz chunker.output.doctype-system nie są konieczne, ale zapewniają poprawną składnię plików HTML dla wszelakich parserów. target.database.document przyjmuje jako argument ścieżkę do pliku XML, gdzie opisywaliśmy strukturę katalogów z książkami. Z kolei parametr current.docid mówi procesorowi, jaki identyfikator nosi konkretnie parsowana przez nas książka – identyfikator ten musi być zgodny z tym, jaki podaliśmy w podanym wcześniej pliku XML.
W wyniku (prawdopodobnie po kilku ostrzeżeniach związanych z niepoprawnym rozwiązaniem linków do innych dokumentacji, na przykład manuali) powinniśmy otrzymać w katalogu html/ kilkanaście gotowych plików HTML.
Domyślnie generowany HTML jest dość prosty, jeśli chcemy go “upiększyć”, warto użyć parametru html.stylesheet przyjmujący jako argument ścieżkę do pliku CSS.
A jeśli chcemy PDF?
Konwersja do PDF jest dwuetapowa – najpierw konwertujemy z DocBook do formatu XSL-FO, który jest dopiero podstawą do wygenerowania PDF.
Początkowe kroki są wspólne – czyli również musimy wygenerować sobie bazę odnośników, stworzyć plik XML, który wiąże targetdoc z odpowiednią bazą. Używamy tylko innego arkusza stylów docbook – z podkatalogu fo/ (chociaż dla etapu generowania bazy nie ma to jeszcze znaczenia):
$ xsltproc --xinclude \\
--stringparam collect.xref.targets "only" \\
/opt/share/xml/docbook/docbook-xsl-ns-1.73.0/fo/docbook.xsl \\
ZFSADMIN.xml
Następnie generujemy plik XSL-FO. Na tym etapie możemy określić formatowanie dokumentu – rodzaje podstawowych czcionek, rozmiar papieru (domyślnie letter), rozmiar czcionki – w moim przypadku wywołanie wygląda tak:
$ xsltproc --xinclude \\
--stringparam paper.type A4 \\
--stringparam body.font.master 8 \\
--stringparam target.database.document "olinkbase.xml" \\
--stringparam current.docid "ZFSADMIN" \\
-o ZFSADMIN.fo \\
/opt/share/xml/docbook/docbook-xsl-ns-1.73.0/fo/docbook.xsl \\
ZFSADMIN.xml
Kolejny etap to już tylko konwersja do formatu PDF z użyciem FOP:
$ fop ZFSADMIN.fo -pdf ZFSADMIN.pdf
Wszelkie “warningi” występujące na tym etapie najczęściej związane są z tym, że elementy określone jako niepodzielne, nieprzenaszalne nie mieszczą się w wyznaczonym obszarze strony. Niestety fop niezbyt dobrze radzi sobie z takimi elementami i często w tych miejscach PDF może nam się trochę rozjechać. Jak sobie z tym poradzić? Poprawić książkę, poprawić fopa, użyć innego programu. ;)
Post a Comment