headerbild blog

speedata Publisher Version 3

Endlich habe ich wieder ein »Major-Release« veröffentlicht. Es ist Zeit für einen kurzen

Rückblick

Wenn man von Version 2.0 ausgeht, sind seit dem ziemlich genau drei Jahre vergangen, in denen es 4 Minor Releases und ca. 150 Patch Releases gab. Das ist durchschnittlich eine Version pro Woche, wobei es natürlich Phasen unterschiedlicher Intensität gab. Interessanterweise kamen bei mir nie Beschwerden aufgrund von Abwärtskompatibilität an, obwohl es kleine inkompatible Änderungen gab (die Betreffen das Cursor-Verhalten bei Objekten, die an den rechten Rand reichen.) Insofern kann ich die umfangreiche Datenbank mit Testfällen als Erfolg ansehen.

Das Entwicklungsmodell ist weitgehend gleich geblieben: Fast alle neuen Features sind Auftragsarbeiten oder Fehlerkorrekturen, die in Kundenprojekten auffallen. In wenigen Fällen kommen Features aus reinem Eigenantrieb. An dieser Stelle ein Dank an die Firmen, die die Entwicklung bezahlt haben.

Seit der Version 2.8 gibt es keine umwälzenden Neuerungen, die meisten Änderungen sind kleine Bugfixes. Ein paar Dinge gibt es doch zu erwähnen:

  • Beliebiges Markup in den Daten kann nun mit CSS versehen werden, siehe den eigenen Beitrag dazu
  • Base64-kodierte Bilder aus den Daten direkt in den Publisher einfügen (s. Beitrag oben).
  • Initialen in Absätzen.
  • Belegen von Zellen bei absoluter Positionierung (keine Voreinstellung).
  • Neuer Befehl <Groupcontents>, um den Inhalt einer Gruppe in eine Tabellenzelle einzufügen.

Blick in die Zukunft

Was bringen die nächsten Versionen? Es gibt noch keine feste Roadmap für den speedata Publisher Version 4.

Mein erster Schritt wird sein, das Handbuch fertig zu stellen. Dazu habe ich schon etwas in einem eigenen Beitrag geschrieben. Es fehlt nicht mehr viel. Ein Verlag ist gefunden, das Stichwortverzeichnis muss ich noch fertig stellen und die Bilder überarbeiten. Ich hoffe, dass das zum Ende August abgeschlossen ist. Das Handbuch wird den Publisher in Version 3 beschreiben und ist inhaltlich auf dem aktuellen Stand (fast jedenfalls).

Einer meiner Wünsche ist es, den CSS-Bereich viel stärker auszubauen. Das Thema PrintCSS ist aktuell und wird es sicherlich auch in einigen Jahren noch sein. Mit dem Publisher habe ich aus meiner Sicht die perfekte Grundlage für diese Art von Software geschrieben. Letztendlich ist der Anspruch an die Satzqualität bei PrintCS niedriger als beim Publisher.

Die Liste der Dinge, die ich machen könnte ist nach hinten offen:

  • Den XML und den XPath-Parser verbessern
  • Die Layoutbeschreibung auch über eine Programmiersprache neben dem XML zugänglich machen (das würde sicherlich etliche Anwender locken)
  • Noch stärker in Richtung Textsatz gehen, z.B. Fußnoten verbessern, unabhängige Flows von Texten erlauben etc. Das würde für Verlage interessant sein.
  • Tagged-PDF für Barrierefreiheit verbessern
  • Docker Image für die einfachere Installation zur Verfügung stellen

Tendenziell wird die Entwicklung, wie oben erwähnt, aber von den Anforderungen getrieben, die ich im täglichen Geschäft habe.

Download

Nicht zu vergessen: Die aktuelle (stabile) Version des Publishers gibt es wie immer unter

https://download.speedata.de/

Das (alte, aber stets aktuelle) Handbuch unter

https://doc.speedata.de/publisher/de/

Viel Spaß damit! Und nicht zögern, bei Fragen einfach eine mailto:gundlach@speedata.de Mail zu schreiben.

von Patrick Gundlach |

ZUGFeRD

Immer wieder erreichen mich Anfragen von Auftraggebern, wo ich kurz grübeln und ausprobieren muss, ob die mit dem Publisher umsetzbar sind. Kürzlich hatte ich eine Anfrage zu elektronischen Rechnungen.

ZUGFeRD (Zentraler User Guide des Forums elektronische Rechnung Deutschland) ist ein Dateiformat für elektronische Rechnungen. Es wird vermutlich nur in Deutschland verwendet, dafür aber recht häufig.

Das Dateiformat besteht aus einer XML-Datei die in eine PDF-Datei eingebettet wird, insofern gibt es hier zwei getrennte »Baustellen«. Die XML-Datei muss genau die Angaben enthalten, die auch in der PDF-Datei sichtbar sind, aber in strukturierter Form. Sowohl die XML-Datei als auch die PDF-Datei müssen einem bestimmten Schema entsprechen.

Die XML-Seite

Für die XML-Datei gibt es entsprechende (XML)Schema-Dateien, die aber leider nicht ausreichend sind, um die Dateien vollständig zu validieren. Hier hätte ich mir ein strengeres Schema gewünscht, für die erste Überprüfung ist es aber auf jeden Fall in Ordnung. Es gibt mehrere Konformitätslevel: Basic, Comfort und Extended, die je nach Typ der darzustellenden Rechnung benutzt werden.

Im Moment interessiert mich die XML-Seite nicht so sehr, dafür um so mehr die PDF-Seite.

ZUGFeRD-PDF

Das ZUGFeRD-PDF baut auf der Spezifikation PDF/A3 auf. Hier fängt das Problem auch schon an, denn die Spezifikation ist nur als verhältnismäßig teure ISO-Norm (ISO 19005-3) verfügbar. Ob ich gewillt bin, 180 Euro für ein Dokument zu bezahlen, das mir möglicherweise nicht wirklich weiter hilft, weiß ich noch nicht.

Unproblematisch ist aber, sich die Beispiele anzusehen, die in der ZUGFeRD-Dokumentation mitgeliefert werden (ZIP-Datei) und eine Art »Reverse-Engineering« zu betreiben.

Das PDF-Format ist eigentlich ein Textformat, aber durch Komprimierung nicht einfach zugänglich. Um die Komprimierung zu entfernen nutze ich qpdf:

qpdf --qdf --object-streams=disable ZUGFeRD_1p0_BASIC_Einfach.pdf uncompressed.pdf

Der Befehl erzeugt die Datei uncompressed.pdf, die man sich mit einem Texteditor anschauen kann. Verändern geht nicht (so einfach), weil die Offsets der einzelnen Objekte in einer Tabelle am Ende des Dokumentes kodiert sind. Wenn sich durch Einfügen oder Löschen von Zeichen die Objekte verschieben, muss die Tabelle neu berechnet werden.

Auf den Aufbau von PDF-Dateien will ich an dieser Stelle nicht eingehen (vielleicht sollte ich das mal in einem eigenen Blogbeitrag machen), daher zeige ich nur Auszüge der Datei. Nur soviel: die PDF-Datei besteht aus einzelnen Objekten. Objekte sind z.B. Zahlen, Zeichenketten und Namen, aber auch komplexere Dinge wie Dictionaries, Arrays und Streams.

Objekte sind entweder direkte Objekte wie die Zeichenkette (Hallo) oder indirekte Objekte, die mit einer Objektnummer referenziert werden wie 6 0 R, das ist eine Referenz auf Objekt 6.

Eine PDF-Datei hat als Einstiegspunkt (Catalog) ein Objekt vom Typ »Dictionary«. Im einfachsten Fall ist das

1 0 obj
<<
  /Type /Catalog
  /Pages 9 0 R
>>
endobj

wobei 9 0 R die Referenz auf ein Objekt ist, das Verweise auf die einzelnen Seiten im PDF enthält. Die Bedeutung der einzelnen Objekttypen sind in der PDF-Spezifikation zu finden.

Das ZUGFeRD-PDF hat noch weitere Einträge im Einstiegspunkt der Datei:

/Metadata 4 0 R
/Names <<
  /EmbeddedFiles <<
    /Names [  (ZUGFeRD-invoice.xml)  6 0 R ]
  >>
>>

Die beiden Einträge /Metadata und /Names sind Teil des Dokumentkatalogs oben. Den Inhalt von /Metadata beschreibe ich weiter unten. Der /Names Eintrag im Katalog beschreibt alle im PDF vorkommenden Namen, auch die der eingebetteten Dateien (hier als einziger Eintrag).

6 0 obj
<<
  /Type /Filespec
  /AFRelationship /Alternative
  /Desc (ZUGFeRD Rechnung)
  /EF <<
    /F  11 0 R
    /UF 11 0 R
  >>
  /F (ZUGFeRD-invoice.xml)
  /UF <feff005a005500470046006500520044002d0069006e0076006f006900630065002e0078006d006c>
>>
endobj

Der Aufbau ist wie oben, ein Dictionary mit Schlüssel/Werte Paaren. Bei ZUGFeRD ist der Name der Rechnung fest auf ZUGFeRD-invoice.xml festgelegt. Der Wert ist auch in /UF in der Kodierung »PDFDocEncoding« (UTF-16BE + BOM) enthalten. Die Einträge unter /EF (für embedded file) zeigen auf die tatsächlich inkludierte Datei.

11 0 obj
<<
  /Type    /EmbeddedFile
  /Subtype /text#2fxml
  /Length  8415
  /Params <<
    /ModDate (D:20170725161353+02'00')
  >>
>>
stream
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryDocument
...
(hier ist die eigentliche ZUGFeRD XML-Datei)
...
</rsm:CrossIndustryDocument>
endstream
endobj

Der Subtype ist der MimeType der Datei in einer PDF spezifischen Kodierung und muss bei ZUGFeRD text/xml sein.

Nun fehlt noch das Metadata-Objekt von oben. Metadaten sind eine formale Beschreibung des sichtbaren Inhalts der PDF-Datei und gehören immer in eine PDF/A Datei. Die Daten sind im XMP-Format bereitzustellen, das wiederum ein XML-Format ist und auf dem RDF-Standard aufbaut. Am einfachsten ist, sich den Inhalt der originalen PDF-Datei anzuschauen und die XMP/RDF-Datei dann nachzubauen. Wichtig ist, dass die Metadaten unkomprimiert im PDF sichtbar sind.

4 0 obj
<<
  /Type /Metadata
  /Subtype /XML
  /Length 3307
>>
stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
...
 </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream
endobj

Für die, die Details wissen wollen: in LuaTeX kann man ein unkomprimiertes Objekt in einer ansonsten komprimierten Datei mit pdf.obj() erzeugen:

pdf.obj({type = "stream",
                 string = metadata,
                 immediate = true,
                 attr = [[  /Subtype /XML /Type /Metadata  ]],
                 compresslevel = 0,
                 })

Hat man dann eine Datei erstellt, die diese Objekte mit den richtigen Inhalten enthält (mit LuaTeX geht das wunderbar), dann kann man diese online im ZUGFeRD Validator überprüfen.

Zusammenspiel mit dem Publisher

Das Feature ist noch in der Entwicklung, bisher habe ich nur einen (funktionierenden) Prototypen fertig gestellt. Dieser ist auf Github zu finden.


Nachtrag: ZUGFeRD ist im Publisher seit der Version 3.1 integriert. Version 3.1 (und später) sind wie gehabt unter https://download.speedata.de/publisher/development/ zu laden.

Die Schnittstelle zur Rechnung ist derzeit wie folgt:

<AttachFile filename="rechnung.xml" description="ZUGFeRD Rechnung" type="ZUGFeRD invoice"/>

Den Rest übernimmt dann der Publisher, der die richtigen PDF-Objekte in die Datei schreibt.

von Patrick Gundlach |

Versionen 2.9.13 und 2.9.14

Heute habe ich nach etwas Ruhe zwei neue Versionen hochgeladen. Die Neuerungen kann ich für ein aktuelles Kundenprojekt gut gebrauchen.

In XML eingebettete Bilder

Die Daten in einem aktuellen Kundenprojekt werden aus einer SQL-Datenbank extrahiert und in XML gewandelt. Zu den Daten gehören auch Bilddaten, die als BLOB ebenfalls in der Datenbank liegen. Nun ist die Frage: wie kommen die Bilder in das PDF? Eine Möglichkeit ist, die Bilder im Dateisystem zu speichern und den Dateinamen in das XML zu speichern. Wir haben einen anderen Weg gewählt und so sind die Bilder Base64 kodiert in den Daten enthalten. Das hat den offensichtlichen Nachteil, dass die XML-Daten nun größer sind (deutlich größer). Der Vorteil ist nicht von der Hand zu weisen: es ist keine separate Datenhaltung der Bilder notwendig. Die XML-Datei ist also self-contained und kann leichter archiviert werden.

Doch nun stellt sich die Frage: wie bekommt man die Bilder aus der XML-Datei heraus in das PDF? Für den Publisher ist es notwendig, dass die Bilder als externe Datei vorliegen. Als großer Freund von XSLT und XPath schiele ich natürlich auf die expath-Erweiterung von Saxon (u.a.), doch der Auftraggeber wollte eine andere Lösung.

Daten extrahieren

Seit Version 2.9.13 gibt es im Publisher zwei neue Funktionen: sd:decode-base64() und sd:filecontents(). Erstere dekodiert einen Base64 String und liefert einen Binärstrom zurück, den ich mit der zweiten Funktion in eine temporäre Datei schreiben kann. Diese Funktion wiederum liefert den Pfad zur temporären Datei zurück. Somit ist es nun leicht, das Bild aus der XML-Datei einzubinden

Gegeben sei eine Datendatei in der folgenden Form (data.xml):

<data>/9j/4AAQSkZJRgABAQEBLAEsAAD/
  4QECRXhpZgAATU0AKgAAAAgABAEPAAIA
  AAAGAAAAPgEQAAIAAAAQAAAARIKaAAUA
  AAABAAAAVIdpAAQAAAABAAAAXAAAAABD
  ....
  U3KQ8AZQwJPHlkRnHyB5Ova9oP/Z
</data>

Dann kann man das Bild extrahieren und laden mit folgendem Code in der Layoutdatei (layout.xml):

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <Record element="data">
    <PlaceObject>
      <Image file="{ sd:filecontents(sd:decode-base64(.)) }" width="4"/>
    </PlaceObject>
  </Record>
</Layout>

Die geschweiften Klammern sind notwendig, damit vorübergehend in den XPath-Modus gesprungen wird. Eine Besonderheit ist hier gegeben: die Bilddatei benötigt keine Dateiendung, der Publisher erkennt das Format am Inhalt.

Das Ergebnis ist wenig überraschend ein Bild:

Das Bild wird indirekt aus der XML-Datei gelesen

Umschalten der Schriftart in den Daten

Ein weiteres schickes Feature (Version 2.9.14) ist die Möglichkeit, in den Daten mit CSS auf andere Schriftarten umzuschalten (font-family). Hintergrund ist die Nutzung von der beliebten Icon-Schriftart FontAwesome. Die Zeichen in der Schriftart lassen sich über einen Code ansprechen, z.B. ist &#xf240; der Code für eine volle Batterie (siehe die Beschreibung auf der Webseite). Um das Zeichen auszugeben, muss man auf die entsprechende Schriftart umschalten. Im Layout würde man das wie folgt machen:

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <LoadFontfile name="FontAwesome" filename="fontawesome-webfont.ttf" />
  <DefineFontfamily name="FA" fontsize="10" leading="12">
    <Regular fontface="FontAwesome"/>
  </DefineFontfamily>

  <Record element="data">
    <PlaceObject>
      <Textblock>
        <Paragraph>
          <Fontface fontfamily="FA"><Value>&#xf240;</Value></Fontface>
          <Value> Die Batterie ist voll geladen</Value>
        </Paragraph>
      </Textblock>
    </PlaceObject>
  </Record>
</Layout>

Wenn man diese Zeichen aber in die Daten einfügen möchte, und nicht in der Layoutdatei, muss der Publisher wissen, wann auf die FontAwesome-Schriftart umgeschaltet werden muss.

Ist die Datendatei z.B. wie folgt aufgebaut:

<data>
  <fa>&#xf240;</fa>  Die Batterie ist voll geladen
  <fa>&#xf243;</fa>  Da geht noch was
</data>

muss man den Publisher anweisen, bei dem (bisher unbekannten) Tag <fa> auf die entsprechende Fontfamilie umzuschalten:

<Stylesheet>
  fa {
     font-family: FA;
  }
</Stylesheet>

Fügt man nun die CSS-Anweisung in das Layout oben ein, wird bei dem <fa>-Tag auf die mit <DefineFontfamily> definierte Schriftart umgestellt.

Mischung von FontAwesome mit einer Textschrift.

Tipp: die OpenType Variante der Schriftart scheint sehr ungewöhnliche Zeichenbreiten zu haben. Die TrueType Variante ist hingegen brauchbar.

Tipp 2: für XSLT 2.0-Freunde habe ich hier ein Stylesheet hinterlegt, das aus <i class="fa fa-..."></i> einen entsprechenden Code erzeugt.

von Patrick Gundlach |

Feature der Woche / Handbuch / Neue Version: 2.9.11

Nach 41 Folgen in der Reihe »Feature der Woche« wird es in diesem Blog etwas andere Schwerpunkte geben. Ich bin zwar mit den Features noch nicht am Ende, aber ich denke, dass ich alle grundlegenden Eigenschaften beschrieben habe. Daher höre ich erst einmal mit der Serie auf.

Handbuch

Derzeit habe ich (neben dem normalen Projektgeschäft, mit dem ich mein Geld verdiene) eine größere Baustelle: das Handbuch wird komplett überarbeitet. Es ist zu 95% fertig, als PDF kommt es auf immerhin schon 300 Seiten. Ich werde es bald öffentlich machen, wenn ich Gelegenheit dazu habe. Bei Interesse kann ich auch eine Vorabversion verschicken. Das Handbuch soll als HTML, PDF, ePub und als gedrucktes Buch erscheinen, und das auf Deutsch und auf Englisch. Soviel sei verraten: es ist eine Kombination aus Einleitung, Kochbuch und Referenz. Die Serie »Feature der Woche« ist fast vollständig in das Buch eingearbeitet, ebenso die Referenz, die derzeit online ist. Dazu kommen natürlich hunderte Korrekturen, Verbesserungen, Querverweise, neue Beispiele etc.

Aktuelle Versionen

Hin und wieder gibt es ja eine neue Version des Publishers, manchmal sogar mehrmals am Tag. Meist sind es nur kleine Änderungen, kleine Bugfixes für spezielle Situationen. Manchmal gibt es aber auch echte neue Features, die ich gerade in einem Projekt benötige. Ich werde nun (hoffentlich regelmäßig) bei einer neuen Version einen kurzen Beitrag über die Änderungen schreiben.

Version 2.9.11

Neu in der Version 2.9.11 ist, dass das Attribut defaultcolor (siehe Feature der Woche Nr. 33) nun so spät wie möglich ausgewertet wird. Damit kann man einen XPath-Ausdruck dort angeben, der den aktuellen Wert bestimmt. Somit ist dies nun möglich:

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <Pagetype name="foo" test="true()" defaultcolor="{$mycolor}">
    <Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
  </Pagetype>

  <Record element="data">
    <SetVariable variable="mycolor" select="'green'"/>
    <PlaceObject>
      <Textblock>
        <Paragraph>
          <Value>Grün?</Value>
        </Paragraph>
      </Textblock>
    </PlaceObject>
    <NewPage/>
    <SetVariable variable="mycolor" select="'blue'"/>
    <PlaceObject>
      <Textblock>
        <Paragraph>
          <Value>Blau!</Value>
        </Paragraph>
      </Textblock>
    </PlaceObject>
  </Record>

</Layout>

Daneben gibt es eine Fehlerkorrektur wenn <Color></Color> keinen Inhalt hat. Außerdem können Initialen (siehe Feature der Woche 38) nun mit komplexen Formen kombiniert werden:

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <Trace grid="yes"/>
  <Pagetype name="foo" test="true()">
    <Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
    <PositioningArea name="text">
      <PositioningFrame width="5" height="20" row="1" column="2"/>
    </PositioningArea>
  </Pagetype>
  <SetGrid nx="20" height="12pt"/>

  <DefineFontfamily name="big" fontsize="24" leading="24">
    <Regular fontface="sans-bold"/>
  </DefineFontfamily>

  <Record element="data">
    <PlaceObject>
      <Box width="2" height="2" backgroundcolor="green"/>
    </PlaceObject>
    <Output area="text" row="2" allocate="auto">
      <Text>
        <Paragraph>
          <Initial fontface="big" color="blue">
            <Value>E</Value>
          </Initial>
          <Value>s war einmal ein großer Drache, der nur deswegen existierte, damit es einen Blindtext gibt.</Value>
        </Paragraph>
      </Text>
    </Output>
  </Record>

</Layout>

Die Initiale nutzt nur den verfügbaren Raum

von Patrick Gundlach |

Feature der Woche, die vollständige Liste

Diese Beiträge sind im Rahmen der Reihe »Feature der Woche« erschienen.

  1. Frame / Rahmen um Objekte
  2. Wiederholender Tabellenkopf und -Fuß (1)
  3. Wiederholender Tabellenkopf und -Fuß (2)
  4. Seitentypen
  5. Datenverarbeitung
  6. Mehrseitige PDF-Dateien einbinden
  7. Virtuelle Seiten
  8. Raster
  9. Absatzform
  10. Seitenverhältnis von Bildern
  11. Seitenzahlen (1)
  12. Seitenzahlen (2, Marker)
  13. Silbentrennung
  14. Schriftarten einbinden
  15. Qualitätssicherung
  16. Textauszeichnung in Daten
  17. Fehlersuche
  18. Bilder einbinden
  19. Dateiorganisation
  20. Beschnittmarken
  21. Hintergrund in Tabellenzellen
  22. Tabellen mit Übertrag
  23. Platzierung von Objekten
  24. Gruppen
  25. Griffmarken
  26. Output oder PlaceObject
  27. QRCode
  28. XProc-Filter
  29. Schema
  30. Font-Alias
  31. Farben
  32. CSS und Daten
  33. Defaultcolor bei Seitentyp
  34. Transformation
  35. Absolute Platzierung
  36. Automatisches Vergrößern von Bildern im Anschnitt
  37. Der Atom-Editor
  38. Initialen
  39. Textformatierung
  40. Regelwerke in Dateien aufteilen
  41. Gruppen in Tabellen
von Patrick Gundlach |

Feature der Woche: Gruppen in Tabellen

Diese Ausgabe kommt gerade noch rechtzeitig, um »Feature der Woche« genannt zu werden.

Diejenigen, die ein wenig Erfahrung mit dem Publisher haben, kennen die virtuellen Flächen oder Gruppen (<Group>). Diese wurden in einer früheren Ausgabe schon thematisiert. Kurz: auf diese beliebig vergrößerbaren Flächen kann man Objekte wie auf einer Seite platzieren, aber ohne, dass sie im PDF erscheinen. Anschließend kann die Gruppen ausmessen und ggf. verwerfen oder in die PDF-Datei ausgeben. Damit kann man Optimierungen fast jedweder Art durchführen.

Die Gruppen konnte man bisher nur über <PlaceObject groupname="..."> ausgeben. Seit der Version 2.9.10 kann man Gruppen auch in Tabellen (genauer: Tabellenzellen, <Td>) ausgeben mit dem Befehl <Groupcontents>. Das ist nur eine kleine Änderung (tatsächlich nur 7 Zeilen Code, der Rest ist Dokumentation und Tests), aber in manchen Situationen sehr effektiv. Das Grundgerüst ist folgendes:

<Record element="data">
  <Group name="foo">
    <Contents>
      <PlaceObject column="1">
        <Image file="_samplea.pdf" width="5"/>
      </PlaceObject>
    </Contents>
  </Group>
  <PlaceObject>
    <Table>
      <Tr>
        <Td><Groupcontents name="foo"/></Td>
      </Tr>
    </Table>
  </PlaceObject>
</Record>

In diesem Fall (es ist ein Beispiel!) ist das natürlich trivial. Wenn aber die Gruppe einen wesentlich größeren Umfang hatte, war es mühselig, das in Tabellen zu wiederholen. Das war nämlich einfaches Copy & Paste, was aus Entwicklersicht natürlich unschön ist. (Der Pragmatismus hat aber bisher gesiegt.)

In einem Beispiel brauchte ich eine Tabelle mit zwei nebeneinanderliegenden Zellen, wobei in der einen Zelle ein Bild ist und dessen Höhe identisch mit dem Inhalt in der anderen Spalte sein sollte.

Das Bild in der rechten Tabellenzelle soll genau so hoch sein wie der Inhalt der linken Spalte.

<Trace objects="yes" grid="yes"/>
<SetGrid height="12pt" nx="20"/>

<Record element="data">
  <Group name="foo">
    <Contents>
      <PlaceObject>
        <Textblock width="2">
          <Paragraph>
            <Loop select="{sd:randomitem(4,5,6,7)}">
              <Value>Text</Value><Br/>
            </Loop>
          </Paragraph>
        </Textblock>
      </PlaceObject>
    </Contents>
  </Group>

  <PlaceObject>
    <Table>
      <Tr>
        <Td><Groupcontents name="foo"/></Td>
        <Td><Image file="_samplea.pdf" height="{sd:group-height('foo')}"/></Td>
      </Tr>
    </Table>
  </PlaceObject>
</Record>

Die Gruppe enthält einige Zeilen mit Text, die Gruppenhöhe ist dank des Rasters, das auf dem voreingestellten Zeilenabstand der Schriftart text eingestellt ist, genau so hoch wie der Text. Das Bild enthält nun anschließend die Höhe, die vorher berechnet wurde.

Bisher war es nötig, den Text erneut in der ersten Tabellenzelle auszugeben.

Dieser Artikel bezieht sich auf den speedata Publisher in der Version 2.9.10. Andere Versionen haben womöglich andere Befehle oder die genannten Befehle zeigen ein anderes Verhalten. Bitte schau im Zweifelsfall in der Anleitung nach.

In der Serie »Feature der Woche« beschreibe ich einmal in der Woche mehr oder weniger nützliche Eigenschaften des Publishers. Kommentare gerne an mich per E-Mail oder einfach im Kommentarfeld.

von Patrick Gundlach |

Feature der Woche: Layoutregelwerke in einzelne Dateien teilen

Ein kurzes, aber sehr praktisches Feature diese Woche.

Man kann das Layoutregelwerk in mehrere Dateien aufteilen. Es gibt zwei Möglichkeiten, die Dateien zusammenzuführen. Auf der Kommandozeile kann man mit --extra-xml eine oder mehrere Layoutregelwerke angeben, die zusätzlich eingelesen werden. Alternativ dazu kann man den Mechanismus über XInclude benutzen, hier im Fall einer Fontdefinition:

von Patrick Gundlach |

LuaTeX, Module und TeXlive 2017

Heute schreibe ich über eine Sache, die nicht unmittelbar mit dem Publisher zu tun hat. LuaTeX kann seit langem C-Module (.so) zur Laufzeit hinzulinken. In der Version kommenden Version 2017 von TeXlive funktioniert das nun auch für Mac OS X. Unter Linux geht das schon länger und unter Windows vermutlich auch (wer mag das testen?). Dieses Feature werde ich in einer zukünftigen Version des Publishers nutzen.

Ein Beispiel, das ich schon mal vor längerer Zeit auf tex.stackexchange.com gepostet hatte, wiederhole ich hier. Es geht um den Zugriff von Datenbanken (hier: sqlite) von LaTeX (LuaLaTeX). Es soll eine einfache Tabelle aus den Daten der Datenbank ausgegeben werden. Dazu wird erst einmal das slite3-Modul von LuaRocks installiert.

LuaRocks

Unter https://luarocks.org/ kann man sich viele Module für Lua herunter laden. Man kann sich das wie ein Paketmanager für Lua vorstellen.

Der Befehl, um z.B. das Modul für die sqlite3 Datenbank herunter zu laden, lautet

luarocks install luasql-sqlite3

Da bei mir die sqlite3 Bibliothek nicht in einem Standardpfad installiert ist, muss ich zusätzlich den Pfad angeben:

luarocks install luasql-sqlite3 SQLITE_DIR=/opt/homebrew/Cellar/sqlite/3.9.2

Dieser ist natürlich für jeden unterschiedlich.

Einbinden des Moduls

Das Modul wird in Lua mit

luasql = require("luasql.sqlite3")

geladen. LuaTeX hat aber keine direkte Verbindung zu LuaRocks, so dass man zwei Möglichkeiten hat, auf das Modul zuzugreifen.

  1. Das Modul in das lokale Verzeichnis kopieren (der einen symbolischen Link zu erstellen)
  2. Einen speziell angepassten Loader für Module zu nutzen. Hier werde ich nicht weiter drauf eingehen, einen funktionierenden Code gibt es unter tex.stackexchange.com/a/219228.

Da das Modul mit luasql.sqlite3 eingebunden wird, sucht LuaTeX im Verzeichnis luasql eine Datei mit dem Namen sqlite3.so (bzw. unter Windows vermutlich mit der Endung .dll). Dazu erstelle ich ein Verzeichnis und den symbolischen Link:

mkdir luasql
cd luasql
ln -s /opt/homebrew/lib/lua/5.2/luasql/sqlite3.so

Die Datenbank

Zum Testen erzeuge ich eine kleine Datenbank mit einer Tabelle und drei Einträgen:

CREATE TABLE people(
name  varchar(50),
email varchar(50)
);
INSERT INTO "people" VALUES('Jose das Couves','jose@couves.com');
INSERT INTO "people" VALUES('Manoel Joaquim','manoel.joaquim@cafundo.com');
INSERT INTO "people" VALUES('Maria das Dores','maria@dores.com');

Diesen Text speichert man unter createdb.txt und erzeugt die Tabellen wie folgt:

sqlite3 luasql-test < createdb.txt

Die Datenbank heißt nun luasql-test.

Und nun der LaTeX-Quellcode

\documentclass{article}
\usepackage{luacode,booktabs}
\begin{document}
\begin{luacode*}

luasql = require("luasql.sqlite3")

env = assert (luasql.sqlite3())
-- connect to data source
con = assert (env:connect("luasql-test"))
-- retrieve a cursor
cur = assert (con:execute"SELECT name, email from people")
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
tex.sprint([[\begin{tabular}{@{}ll@{}}\toprule]])
tex.sprint([[Name & email \\\midrule]])
while row do
  tex.sprint(-2,row.name)
  tex.sprint("&")
  tex.sprint(-2, row.email)
  tex.sprint("\\\\")
  -- reusing the table of results
  row = cur:fetch (row, "a")
end
tex.sprint([[\bottomrule\end{tabular}]])
-- close everything
cur:close()
con:close()
env:close()
\end{luacode*}
\end{document}

Der Code ist zwar etwas unübersichtlich, aber gar nicht so kompliziert. Es wird praktisch nur Lua-Code ausgeführt. Dort wird die (oben erstellte) Datenbank geöffnet, die SQL-Abfrage ausgeführt und in einer Schleife mit speziellen tex.sprint()-Befehlen LaTeX-Code erzeugt.

Solange die Tabelle in der Variablen row existiert, werden die einzelnen Inhalte ausgegeben. Die -2 bei tex.sprint() bedeutet, dass die Sonderzeichen wie & oder # keine besondere Bedeutung haben und einfach so ausgegeben werden (für TeXniker: die Catcodes haben alle den Wert 12 - other).

Um diese Schleife herum wird eine tabular-Umgebung erzeugt, die man von LaTeX her kennt.

Die übrigen Zeilen dienen nur zum Öffnen und Schließen der Datenbank. Die Dokumentation zu luasql ist auf der Seite des Kepler-Projekts zu finden.

Die Ausgabe aus unserer TeX-Datei von oben.

von Patrick Gundlach |

Feature der Woche: Textformatierung

Diese Woche geht es ganz allgemein um Textformatierung.

Es gibt zahlreiche Möglichkeiten, die Formatierung der Texte zu beeinflussen. Die Schalter für die Schriftschnitte (<Fontface fontface="...">) wurden in Feature der Woche: Schriftarten einbinden vorgestellt.

Mit einer ähnlichen Funktionalität gibt es die folgenden Befehle:

<Sub> und <Sup>
Tiefgestellter und hochgestellter Text.
<Fontface>
Schaltet vorübergehend auf eine andere Schriftart um.
<Color>
Gibt den eingeschlossenen Text in einer anderen Farbe aus.
<A>
Erzeugt ein Hyperlink.
<HSpace>
Fügt einen dehnbaren Leerraum (mit oder ohne Punkte) ein.
<U>
Unterstreichen.

Es folgt ein Beispiel, das die Auszeichnungen enthält.

<PlaceObject>
  <Textblock>
    <Paragraph>
      <Value>Text</Value>
      <Sub><Value>Tiefergestellt</Value></Sub>
      <Value> </Value>
      <Sup><Value>Hochgestellt</Value></Sup>
      <Value> </Value>
      <U><Value>Unterstrichen</Value></U>
      <Value> </Value>
      <Color name="green"><Value>Grün</Value></Color>
      <Value> </Value>
      <A href="https://www.speedata.de">
        <Value>Link zur Homepage</Value>
      </A>
      <HSpace leader=" . "/>
      <Value>rechter Rand.</Value>
    </Paragraph>
  </Textblock>
</PlaceObject>

Verschiedene Textauszeichnungen

Aufzählungslisten

Anstelle eines Absatzes kann auch eine Aufzählungsliste erscheinen. Diese wird mit <Ol> bzw. <Ul> für eine Liste mit Nummerierung (ordered list) und eine Liste mit Punkten (unordered list) angegeben. Die einzelnen Punkte müssen mit <Li> ausgezeichnet werden.

<PlaceObject>
  <Textblock>
    <Ol>
      <Li><Value>Eins</Value></Li>
      <Li><Value>Zwei</Value></Li>
    </Ol>
    <Ul>
      <Li><Value>Eins</Value></Li>
      <Li><Value>Zwei</Value></Li>
    </Ul>
  </Textblock>
</PlaceObject>

Listen

TIPP: Dieses Feature ist noch nicht wirklich robust. Die Listen können (derzeit) nicht geschachtelt werden. Es empfiehlt sich zu schauen, ob die Listen auch korrekt ausgegeben werden.

Verhindern von Textumbruch

Manche Überschriften und Eigennamen sollen nicht umbrochen werden. Dafür gibt es den Befehl <NoBreak>, der auf verschiedene Weisen einen Umbruch unterdrückt. Ein etwas übertriebenes Beispiel ist:

<PlaceObject>
  <Textblock>
    <Paragraph>
      <Value>Ein langer Text, der nur zur Illustration dient, </Value>
      <NoBreak><Value>während dies nicht umbrochen werden darf.</Value></NoBreak>
    </Paragraph>
  </Textblock>
</PlaceObject>

Die Voreinstellung bei NoBreak ist, dass der Teil zusammen hängen muss.

Alternativ kann man durch eine Vorgabe der maximalen Breite die Schriftgröße verringern oder den Text mit Auslassungspunkten kürzen.

<Textblock>
  <Paragraph>
    <Value>Ein langer Text, der nur zur Illustration dient, </Value>
    <NoBreak maxwidth="6" reduce="cut" text="...">
      <Value>während dies nicht umbrochen werden darf.</Value>
    </NoBreak>
  </Paragraph>
</Textblock>

Hier wird per cut der Text abgeschnitten und mit dem angegebenen Text aufgefüllt.

Umbrechen von URLs

Der Befehl <URL> dient zum leichteren Umbrechen von URLs. Es darf vornehmlich an Schrägstrichen (/) umbrochen werden, außerdem werden keine Trennstriche eingefügt. Es wird kein Hyperlink erzeugt, dafür ist der Befehl <A> zuständig.

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <SetGrid nx="40" ny="10"/>
  <Trace grid="yes"/>
  <Pageformat width="90mm" height="5cm"/>
  <Record element="data">
    <PlaceObject>
      <Textblock>
        <Paragraph>
          <URL><Value>https://download.speedata.de/publisher/development/</Value></URL>
        </Paragraph>
      </Textblock>
    </PlaceObject>
  </Record>
</Layout>

ergibt

URLs dürfen nicht wie normaler Text behandelt werden.

Dieser Artikel bezieht sich auf den speedata Publisher in der Version 2.9.8. Andere Versionen haben womöglich andere Befehle oder die genannten Befehle zeigen ein anderes Verhalten. Bitte schau im Zweifelsfall in der Anleitung nach.

In der Serie »Feature der Woche« beschreibe ich einmal in der Woche mehr oder weniger nützliche Eigenschaften des Publishers. Kommentare gerne an mich per E-Mail oder einfach im Kommentarfeld.

von Patrick Gundlach |

Feature der Woche: Initialen

Mal wieder ein brandneues Feature diese Woche: Initialen. Das sind meist größere oder verzierte Buchstaben am Anfang eines Abschnittes. Häufig werden Initialen benutzt, um Textanfänge zu markieren.

Der Publisher erlaubt nun innerhalb von <Paragraph> einen neuen Befehl <Initial>, mit dem man solch einen Effekt erreichen kann.

Hier eignet sich ein Beispiel, um das zu illustrieren:

Eine Initiale

von Patrick Gundlach |