2012-12-04 5 views
5

Suche mehr Funktionen zu erreichen, um die Ausgabe meines Programms zu versüßen. Ich möchte den Hintergrund eines Textspalte auf eine bestimmte Farbe setzen, so dass es mehr klar ist, dass Spalten zusammengehören.Wie kann ich Text in Python wie in Illustrator formatieren?

Ein Bild sagt mehr als tausend Worte: ich das konvertierende:

Pos. :123456789
Name. :ABCDEFGHIJKLMNO 
Str. :SOMESTRINGSOMET <---- indented by half a row, Column number superscripted 
Str. :SOM  SOMET 
Str. :SOMESTRIN ET 

dazu:

example

Wie kann ich tun, dass mit Python? Gibt es einen Rahmen, der mir dies erlaubt? Ich habe dies in Latex umgewandelt, aber ich kann die hochgestellten Zahlen nicht funktionieren. Sie müssen über dem Text sein, aber nicht als ein Zeichen handeln, da es eine Beziehung zwischen den Spalten des Bildes gibt.

Beispiel: A ist an Position 1. Es hat als Eigenschaften S und O, deshalb ist es oben auf diesen zwei und deshalb gibt es einen Einzug von einem halben Zeichen. S hat den Exponenten 170, T den Exponenten 185.

besonders hart ist auch der Teil hat, wo die Str Teil verschoben wird eine halbe character.I möchte ein Beispiel haben, um diese in mein Programm zu integrieren.

+3

Ausgabe auf LaTeX oder einem anderen Satz :)/Werkzeug Formatierung scheint, wie die Art und Weise zu gehen. Python kommt nicht mit einer Satzbibliothek. –

+0

danke für die schnelle antwort. Ich habe die "richtige" Grafik mit dem Illustrator gemacht. aber ich kann gerade nicht, dass dieses Zeug sogar mit Latex zu arbeiten :(wird aktualisiert, sobald ich einen Schritt weitergehe. – tarrasch

+0

Ist diese Frage auf mono spaced Fonts beschränkt? – mmgp

Antwort

2

Es ist möglich, mit kniffligen Lösungen zu kommen, Mono Abstand Schriftarten bedenkt, dass Ihr Problem lösen kann. Aber sie warten nur darauf, zu versagen. Die grauen Spalten in Ihrem Beitrag können genau wie in Ihrer Figur hinzugefügt werden, aber ich habe mich entschieden, die Farben in den Buchstaben nicht zu ändern (einfach weil ich es auf diese Weise besser lesbar finde).

ist hier etwas möglich mit PIL zu kommen:

enter image description here

geringfügige Änderung des Fonts:

enter image description here

Mehr "severe" font Änderungen nächsten, alle mit dem Code erzeugt wie es ist.

enter image description here     enter image description here

Und nächstes ist der Code, diese Zahlen zu erzeugen. Ich habe es nicht wirklich schön gemacht und es kann auf viele Arten verbessert werden. Betrachten Sie dies als ein Beispiel dafür, was Sie tun müssen, um vielleicht eine Lösung für Ihr Problem zu finden. Um mit jeder Art von Schrift zu arbeiten, benötigen Sie ein aktuelles Satzsystem wie LaTeX.

import sys 
import Image, ImageDraw, ImageFont 


# Assumption: some other piece of code separates the data in the following 
# format. 
line1 = [("Pos. :", 0), ("123456789", 0)] 
line2 = [("Name. :", 0), ("ABCDEFGHIJKLMNO", 0)] 
line3 = [("Str. ", 0), (":", -0.5), ("SOMESTRINGSOMEST", -0.5)] 
line4 = [("Wave 1:", 0), ("_XXXX_X____X_X_", 0)] 
line5 = [("Wave 2:", 0), ("__XX_XXX_X__X_X", 0)] 
line_data = [line1, line2, line3, line4, line5] 
# Texts to draw over the last element, in specific positions, 
# of lines present in line_data. 
subscript = { 
     2: { # Meaning: third item in line_data 
      0: "170", # Meaning: draw "170" over the first char 
      len(line3[-1][0]) - 1: "185", # Draw "185" over the last char 
      7: "180", # Meaning: draw "180" over the eight char 
      }, 
     4: {5: "hi"}, 
     3: {6: "ops"} 
     } 

# If the following fonts are not mono spaced, you are going to suffer. 
# 
# Normal font. 
font = ImageFont.truetype('FreeMono.ttf', 40) 
# Font for subscript. 
font_tiny = ImageFont.truetype('FreeMono.ttf', 20) 


im = Image.new("RGBA", (1000, 1000), 'white') 
draw = ImageDraw.Draw(im) 
line_offset = 4 
start_y = 6 

width_A, height_A = font.getsize('A') 
_, height_tiny_A = font_tiny.getsize('A') 

# Collect even columns from the last item of list line1. 
even_columns = [] 
x = 0 
for i, (text, _) in enumerate(line1): 
    for j, letter in enumerate(text): 
     if i == len(line1) - 1 and not j % 2: 
      even_columns.append(x) 
     x += width_A 

# Write all lines. 
width = 0 
l_start_y = start_y 
for di, data in enumerate(line_data): 
    x = 0 
    for i, (text, xoff) in enumerate(data): 
     for j, letter in enumerate(text): 
      # Apply x offset. 
      extra = width_A * xoff 
      draw.text((x + extra, l_start_y), letter, font=font, fill='black') 
      x += width_A 
    width = max(x, width) 
    l_start_y += height_A + line_offset 

# Collect letter positions from the lines that will have subscripts. 
letter_pos = {} 
for k in subscript: 
    letter_pos[k] = {} 
    x = sum(len(text) for text, _ in line_data[k][:-1]) * width_A 
    text, xoff = line_data[k][-1] 
    for i in range(len(text)): 
     extra = width_A * xoff 
     letter_pos[k][i] = x + extra 
     x += width_A 
# Write all subscripts. 
for k, v in subscript.items(): 
    line = line_data[k] 
    for pos, text in v.items(): 
     x = letter_pos[k][pos] 
     y = start_y + (line_offset + height_A) * k 
     y -= height_tiny_A * 0.4 # XXX A poor heuristic that worked here. 
     draw.text((x, y), text, font=font_tiny, fill='black') 
     width = max(width, int(x + font_tiny.getsize(text)[0])) 

# Draw grey columns. 
columns = Image.new(im.mode, im.size, 'white') 
mask = Image.new("L", im.size, 'white') 
for x in even_columns: 
    columns.paste((128, 128, 128), (x, line_offset, x + width_A, l_start_y)) 
    mask.paste(164, (x, line_offset, x + width_A, l_start_y),) 
im = Image.composite(im, columns, mask) 

# Crop and save the resulting image. 
im.crop((0, 0, width, l_start_y + 2)).save(sys.argv[1]) 
+0

awesomeness. genau das, was ich suchte. Was, wenn ich wollte addiere mehr Zeilen wie Str unter? würde ich nur 'für di ändern, Daten in enumerate ([line1, line2]):' für di, Daten in enumerate ([line1, line2, linex]):? – tarrasch

+0

Ja, das wäre Sie müssen aber auch die Zeichnung an 'für k, v in line3_1_top.iteritems() anpassen: ...'. Ich würde mit einem 'num_lines = x' beginnen, wobei' x' für die Gesamtzahl der Zeilen steht schrieb, wie 4 in Ihrem Fall und 3 in meinem Beispiel. Und ändern Sie den Code für das Zeichnen der Indexe für die Handhabung dieser. – mmgp

+0

eigentlich brauche ich das nicht zu wiederholen. Ich möchte nur einige weitere Zeilen unten in der gleichen Weise wie str hinzufügen. Dein Code ist ein Level über meiner Fähigkeit :-). Ich werde das Kopfgeld vergeben, sobald ich es zur Arbeit bekommen habe. Ich möchte auch das line_3_1 Bit alle 10 Zeichen oder so wiederholen, wie die Spaltennummern – tarrasch

1

Dies ist eher eine LaTeX-Frage als eine Python-Frage - d. H., Wenn Sie das Markup bestimmen, das Ihr Python-Skript erzeugen soll, dann ist es ziemlich einfach, es zu erzeugen.

In diesem Fall, ich denke, Sie könnten wahrscheinlich die gewünschten Effekte mit einer ziemlich komplexen Tabelle erhalten (\begin{table}...\end{table}), wobei jede Ihrer Zellen zwei Spalten umfasst, und eine Spalte als Offset verwendet wird, um das "halbe Zeichen " Sie wollen. Es würde mich nicht überraschen, wenn es einen einfacheren Weg gibt, dies in LaTeX zu tun (das hat viel mehr Bibliotheken, als ich in meinem Kopf behalten kann), aber das ist das, was einem einfällt. So Tisch würde wie folgt aussehen:.

+------+--+--+--+--+--+--+--+ 
| pos. | | 1 | 2 | 3 |  ... 
+------+--+--+--+--+--+--+--+ 
| name.| | A | B | C |  ... 
+------+--+--+--+--+--+--+--+--+ 
|  | 170 |  |  |  | ... 
+------+--+--+--+--+--+--+--+--+ 
| Str. | S | O | M | E | ... 
+------+--+--+--+--+--+--+--+--+ 

(Wo + s zeigen an, wo die tatsächlichen Spalten, und die meisten Zellen überspannen zwei Spalten der Zeile mit „170“ an \tiny oder so Befehl verwenden würde.

)

Mein Vorschlag wäre, zu spielen, um mit einer LaTeX-Datei zuerst von Hand zu erzeugen, das tut, was Sie wollen (oder eine andere Formatierung Sprache Ihrer Wahl Datei); und dann sorgen Sie sich darum, etwas Python-Code zu schreiben, um es zu erzeugen.

0

Während PIL ok für einfache Sachen funktioniert, haben Sie viel mehr Optionen, wenn Sie SVG verwenden. Sie können pySVG (handy pySVG tutorial) oder svgwrite verwenden, um Ihre SVG programmgesteuert oder nur print als Text zu erstellen. Verwenden Sie dann ImageMagick (entweder in der Befehlszeile als convert oder von Python mit pythonmagicwand), um das SVG auf einen beliebigen Raster-Typ zu rendern. Während die Feinabstimmung der SVG Sie es mit einem Texteditor bearbeiten und in einem Web-Browser sie betrachten

# make some text in any font, any size, any effects 
import pysvg 
s = svg() 
myStyle = StyleBuilder() 
myStyle.setFontFamily(fontfamily="Verdana") 
myStyle.setFontSize("5em") 
myStyle.setFilling("blue") 
t1 = text("Hello World", 0, 100) 
t1.set_style(myStyle.getStyle()) 
s.addElement(t1) 
s.save('test.svg') 

from pythonmagickwand.image import Image 
img = Image('test.svg') 
img.format = 'PNG' 
img.save('test.png')