[PYTHON] Generieren Sie aus Textdaten ein vertikales Bild eines Romans

(Ergänzung 2019.12.14)

Das Kissen kann vertikal auf Japanisch geschrieben werden, mindestens in Ver6 oder höher (+ raqm 0.7 oder höher). Bitte beachten Sie, dass der Inhalt dieses Artikels nicht mehr aktuell ist.

Machen

yosuruni.png

Ich habe darüber nachgedacht.

Verfassung

Die wichtigsten verwendeten Bibliotheken sind wie folgt.

Beschreiben Sie die Auflösung des generierten Bildes und das Layout der Spalten in XML. Es gibt kein bestimmtes Format, auf dem es basiert, und es ist ein Original, das entsprechend entschieden wurde. Verwenden Sie die XML-Bibliothek, um sie zu analysieren. Der Text wird in einfachem Text geschrieben, und Rubin- und Seitenpunkte werden im Text in HTML-Tags geschrieben. Verwenden Sie HTMLParser, um dies zu analysieren. Ich habe das Gefühl, dass eine der Bibliotheken mit beiden umgehen kann, aber ich habe beschlossen, beide zum Lernen zu verwenden. Verwenden Sie Pillow, eine Bildverarbeitungsbibliothek, um Zeichen zu zeichnen. Natürlich kann nicht geholfen werden, aber Pillow unterstützt vertikales Schreiben überhaupt nicht, daher mache ich viel Versuch und Irrtum (Ausschneiden), um vertikal zu schreiben.

Layout und Körper

Die XML-Datei, die das Layout und den Text bestimmt, sieht wie folgt aus.

yosuruni_layout.xml


<novel width="1920" height="960" margin_up="0.1" margin_bottom="0.1" margin_left="0.05" margin_right="0.05">
    <columnchain name="Main" fontsize="36" direction="VERTICAL" linespace="2.0" color="#101000">
        <column refp="UP_RIGHT" reflh="MARGIN_RIGHT" reflv="MARGIN_UP" offsetx="LIVEAREA_H:0" offsety="LIVEAREA_V:0" sizew="LIVEAREA_H:1.0" sizeh="LIVEAREA_V:1.0"/>
    </columnchain>
    <text columnchain="Main" src="yosuruni.xml" />
</novel>

yosuruni.xml


Mein Kind, das vier Jahre alt war, ist gut lesbar geworden. Ich denke von nun an daran, viele Bücher zu lesen, aber ich habe bisher nicht viel gelesen, also wusste ich nicht, welche Art von Buch ich wählen sollte.

Aufgrund verschiedener Gedanken wurde mir klar, dass ich selbst eine Geschichte schreiben und lesen lassen sollte. Obwohl ich überhaupt kein Buch gelesen habe, frage ich mich, ob ich eine Geschichte schreiben kann, aber es besteht kein Zweifel, ob ich "Oshiri" oder "Unko" angemessen schreibe. Weil ich 4 Jahre alt bin.

Übrigens, als ich anfing, mit einer Notizblockanwendung zu schreiben, war es völlig horizontales Schreiben<d>Nicht wie</d>.. Wenn es nicht vertikal geschrieben ist, als "Lesematerial"<r val="Spaß">Atmosphäre</r>Ich kann es nicht fühlen und es macht keinen Spaß zu sehen. Also suchte ich nach einem Editor, der vertikal schreiben kann, aber ich konnte nichts finden, was so schien.

In diesem Fall bleibt nichts anderes übrig, als es zu tun. Eine App wie ein Editor ist unmöglich, aber ich denke, dass dies mit einem Tool möglich ist, das einfachen Text in ein vertikales Bild konvertiert ...

Wenn Sie im Layout die Spaltenelemente im Spaltenkettenelement erhöhen, werden die Spalten vergrößert und der Text wird in der Reihenfolge der Spaltenbeschreibung übertragen.

Das Layout und der Text werden grundsätzlich anhand der folgenden Routinen analysiert.

Layoutanalyse.py


import xml.etree.ElementTree as ET

#Analysieren Sie XML, um den Elementbaum zu erhalten
tree = ET.parse(xml_path)
#Holen Sie sich das Root-Element. Sie erhalten ein neues Element
novel_element = tree.getroot()

#Beziehen Sie sich hier auf die Attribute des neuen Elements, um den Einstellwert zu erhalten.

#Holen Sie sich das Columnchain-Element in das neuartige Element
for cc_element in novel_element.iter("columnchain"):
    #Beziehen Sie sich hier auf das Attribut des Spaltenkettenelements, um den Einstellungswert zu erhalten.

    #Holen Sie sich das Spaltenelement in das Spaltenkettenelement
    for c_element in cc_element.iter("column"):
        #Beziehen Sie sich hier auf das Attribut des columnc-Elements, um den Einstellungswert zu erhalten.

#Holen Sie sich das Textelement in das neuartige Element
for text_element in novel_element.iter("text"):
    #Beziehen Sie sich hier auf das Attribut des Textelements, um den Einstellungswert zu erhalten.

Körperanalyse.py


from html.parser import HTMLParser

class TextParser(HTMLParser):

    def __init__(self):
        super().__init__()

    def handle_starttag(self, tag, attrs):
        if tag == "ruby" or tag=="r":
            #Erkennen des Beginns des Ruby-Tags

        if tag == "dot" or tag=="d":
            #Erkennt den Beginn eines Seitenpunkt-Tags

    def handle_endtag(self, tag):
        if tag == "ruby" or tag == "dot" or tag == "r" or tag == "d":
            #Erkennen Sie das Ende des Tags

    def handle_data(self, data):
        #Datenerfassung in Tags. Der Text selbst oder Rubin(Pseudonym lesen)Erhalten

class Text():

    def __init__(self, source):
        parser = TextParser()
        parser.feed(source)

Ausführungs- und Ausgabeergebnis

Das Folgende ist beispielsweise ein vertikal langes Layout mit 3 Zeilen. (Da es sich um ein Beispiel handelt, ist die Auflösung niedrig. Die Zeichen sind 12 Punkte bei 320 x 720)

yosuruni_layout.xml


<novel width="320" height="720" margin_up="0.1" margin_bottom="0.1" margin_left="0.05" margin_right="0.05">
    <columnchain name="Main" fontsize="12" direction="VERTICAL" linespace="2.0" color="#101000">
        <column refp="UP_RIGHT" reflh="MARGIN_RIGHT" reflv="MARGIN_UP" offsetx="LIVEAREA_H:0" offsety="LIVEAREA_V:0" sizew="LIVEAREA_H:1.0" sizeh="LIVEAREA_V:0.3"/>
        <column refp="UP_RIGHT" reflh="MARGIN_RIGHT" reflv="MARGIN_UP" offsetx="LIVEAREA_H:0" offsety="LIVEAREA_V:0.35" sizew="LIVEAREA_H:1.0" sizeh="LIVEAREA_V:0.3"/>
        <column refp="UP_RIGHT" reflh="MARGIN_RIGHT" reflv="MARGIN_UP" offsetx="LIVEAREA_H:0" offsety="LIVEAREA_V:0.7" sizew="LIVEAREA_H:1.0" sizeh="LIVEAREA_V:0.3"/>
    </columnchain>
    <text columnchain="Main" src="yosuruni.xml" />
</novel>
$ python NovelFE.py yosuruni_layout.xml

Dies gibt das folgende Bild aus.

test0.png

Wenn die Auflösung niedrig ist, schwankt die Position der Zeichen leicht, was ärgerlich ist.

Vertikale Zeichnung

Wie oben erwähnt, ermöglicht Pillow horizontales Schreiben, jedoch kein vertikales Schreiben. Also habe ich beschlossen, vertikal zu schreiben. Mit anderen Worten, es zeichnet Zeichen für Zeichen, während die Position in vertikaler Richtung verschoben wird.

Ich habe Gensho Antic als Schriftart verwendet. Eine Cartoon-Schriftart, die vertikales Schreiben unterstützt.

Wenn ich jedoch versuche, es zu zeichnen, ist es natürlich,

ng.png

Horizontale Schreibschriftzeichen wie Klammern, Satzzeichen und kleine "tsu" werden verwendet. In der Kissenbibliothek gibt es keine Möglichkeit, vertikales Schreiben anzugeben, daher werden für vertikales Schreiben keine Glyphen verwendet.

Als schnelle Idee, was zu tun ist, kam mir die Idee, die Schriftartdatei selbst zu manipulieren und die horizontalen Glyphen zwangsweise durch vertikale Glyphen zu ersetzen.

pip install fonttools

Installieren Sie die Python-Fontools fonttools (ttx). Wenn Sie mit dem Befehl ttx eine Schriftartdatei angeben, wird diese in XML konvertiert.

% ttx GenEiAntiqueN-Medium.otf 
Dumping "GenEiAntiqueN-Medium.otf" to "GenEiAntiqueN-Medium.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'name' table...
Dumping 'cmap' table...
Dumping 'post' table...
Dumping 'CFF ' table...
Dumping 'BASE' table...
Dumping 'GDEF' table...
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'VORG' table...
Dumping 'hmtx' table...
Dumping 'vhea' table...
Dumping 'vmtx' table...

Die diesmal verwendete Schriftart ist im OpenType-Format. Überprüfen Sie daher die Gliederung der folgenden Spezifikationen.

Einführung in OpenType-Spezifikationen (Teil 2) [Einführung in OpenType-Spezifikationen (Teil 2)] (http://qiita.com/496_/items/4f8327fe741cf0c87736) [Einführung in OpenType-Spezifikationen (Teil 1)] (http://qiita.com/496_/items/f6efb650dcf7e9d2dfe4)

Aus dem oben Gesagten sind die von ttx generierten wichtigen XML-Dateien GSUB und cmap.

OpenType enthält ungefähr Glyphen (Schriftarten) mit IDs. Die cmap-Tabelle enthält eine Entsprechungstabelle mit den Glyphendaten-IDs, die den Zeichencodes (z. B. Unicode) entsprechen. Wenn sich in der GSUB-Tabelle das unter einer bestimmten Bedingung verwendete Glyphen ändert, wird auch die Entsprechungstabelle zwischen der Glyphen-ID der Änderungsquelle und der Glyphen-ID des Änderungsziels angezeigt.

Daher wird die Korrespondenztabelle, die die Glyphen-ID zeigt, die beim vertikalen Schreiben ersetzt werden soll, aus der GSUB-Tabelle extrahiert, und basierend darauf wird die Glyphen-ID der Korrespondenztabelle in der cmap-Tabelle ersetzt. Dann sollten Sie sich bedingungslos auf das Symbol für vertikales Schreiben beziehen können.

Schreiben wir ein Skript zur Konvertierung.

otfconv.py


import argparse
import xml.etree.ElementTree as ET

parser = argparse.ArgumentParser()
parser.add_argument("infile")
args = parser.parse_args()

tree = ET.parse(args.infile)
root = tree.getroot()

list_index = []
cid_replace_dic = {}

for gsub_elements in root.iter('GSUB'):
    for featurerecords in gsub_elements.iter('FeatureRecord'):
        for featuretags in featurerecords.iter('FeatureTag'):
            if featuretags.attrib['value'] == "vert" or \
                    featuretags.attrib['value'] == "vrt2" or \
                    featuretags.attrib['value'] == "vtrt":
                for lookuplistindexs in featurerecords.iter('LookupListIndex'):
                    if not lookuplistindexs.get('value') in list_index:
                        list_index.append(lookuplistindexs.get('value'))

    for lookup in gsub_elements.iter('Lookup'):
        if lookup.get('index') in list_index:
            for substitution in lookup.iter('Substitution'):
                cid_replace_dic[substitution.get('in')] = substitution.get('out')


for cmap in root.iter('cmap'):
    for maps in cmap.iter('map'):
        if maps.get('name') in cid_replace_dic.keys():
            maps.set('name', cid_replace_dic[maps.get('name')])

tree.write("output.xml")
$ python otfconv.py GenEiAntiqueN-Medium.ttx

Hoffentlich wird output.xml erstellt und ich werde es mit ttx wieder in die OpenType-Datei konvertieren. Übrigens, als ich es tat, bekam ich einen Konvertierungsfehler, es sei denn, ich habe die folgende Zeile am Anfang hinzugefügt. (Das hat funktioniert, also habe ich nicht zu sehr ins Detail geschaut.)

<?xml version="1.0" encoding="UTF-8"?>

Verwenden Sie ttx, um von xml zu otf zurückzukehren.

$ ttx -o TateFont.otf output.xml

Dann

test.png

Ich konnte so schreiben.

Einige erforderliche Funktionen

Ich dachte, dass zumindest Rubin und Verbotsverarbeitung notwendig sind, um daraus einen Roman zu machen. Als Bonus ist es auch ein Nebenpunkt. Rubi ist etwas problematisch, denn wenn die Zeichenhöhe des Rubi die entsprechende Zeichenhöhe des Textes überschreitet, muss der Abstand zwischen den Zeichen im Text vergrößert werden.

test0.png

Das andere ist die Unterstützung mehrerer Seiten. Wenn der Text nicht auf eine Seite passt, versuchen Sie, mehrere Bilder mit demselben Layout zu generieren.

Jetzt können Sie eine Geschichte schreiben.

schließlich

Recommended Posts

Generieren Sie aus Textdaten ein vertikales Bild eines Romans
Generieren Sie ein MeCab-Wörterbuch aus Nico Nico Encyclopedia-Daten
Extrahierter Text aus dem Bild
Generieren Sie gemeinsam Bildtext
Erstellen Sie einen Datenrahmen aus den erfassten Textdaten des Bootsrennens
[Python] Extrahieren Sie Textdaten aus XML-Daten von 10 GB oder mehr.
Ich habe versucht, mit PI Fu aus einem Bild ein 3D-Modell einer Person zu erstellen
Generieren Sie ein Docker-Image mit Fabric
Machen Sie eine Santa-Kennung aus einem Santa-Bild
Collage automatisch aus Bildliste generieren
[Spark Data Frame] Ändern Sie eine Spalte von horizontal in vertikal (Scala).
Ich habe eine Untertiteldatei (SRT) aus JSON-Daten von AmiVoice erstellt
Generieren Sie eine Liste aufeinanderfolgender Zeichen
So senden Sie ein visualisiertes Bild der in Python erstellten Daten an Typetalk
Eine Geschichte von einer Person, die von Anfang an auf Datenwissenschaftler abzielte
python + faker Generiere zufällig einen Punkt mit einem Radius von 100 m von einem bestimmten Punkt
Erfassung von Pflanzenwachstumsdaten Erfassung von Daten von Sensoren
Generieren Sie eine Klasse aus einer Zeichenfolge in Python
Ein Memorandum über Probleme beim Formatieren von Daten
"Minecraft, wo Yaji fliegt" Generieren Sie geeigneten Text mit Deep Learning ~ Daten sammeln ~
Ich habe versucht, automatisch eine Portverwaltungstabelle aus L2SW Config zu generieren
Ein Memo zum Generieren dynamischer Klassenvariablen aus Wörterbuchdaten (dict), die in Python3 nur Standardtypdaten enthalten
Generieren und veröffentlichen Sie Dummy-Bilddaten mit Django
Laden Sie Bilder aus einer Textdatei herunter, die die URL enthält
Ein Memorandum zum Aufrufen von Python aus Common Lisp
So generieren Sie ein Python-Objekt aus JSON
Erkennen Sie allgemeine MIDI-Daten von einer großen Menge von MIDI
Datenbereinigung 3 Verwendung von OpenCV und Vorverarbeitung von Bilddaten
Aufgezeichnete Umgebung für die Datenanalyse mit Python
Übergang von Baseball aus Daten gesehen
Extrahieren Sie mit Python Daten von einer Webseite
Versuchen Sie, mit matplotlib aus den Daten von "Schedule-kun" eine Kampfaufzeichnungstabelle zu erstellen.
Rufen Sie mithilfe der API eine Liste der GA-Konten, -Eigenschaften und -Ansichten als vertikale Daten ab
Ermitteln Sie die maximale Anzahl von Zeichen in mehrzeiligem Text, die in einem Datenrahmen gespeichert sind