2012-12-04 8 views
5

Sto cercando di ottenere diverse funzionalità per addolcire l'output del mio programma. Voglio impostare lo sfondo di una colonna di testo su un determinato colore in modo che sia più chiaro che le colonne appartengono insieme.Come posso formattare il testo in python come farei con Illustrator?

una foto vale più di mille parole: voglio convertire questo:

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

a questo:

example

Come posso fare che l'utilizzo di Python? C'è un quadro che mi permette di fare questo? L'ho convertito in lattice, tuttavia non riesco a far funzionare i numeri in apice. Devono essere al di sopra del testo, ma non agire come un personaggio, poiché esiste una relazione tra le colonne del picure.

Esempio: A è in posizione 1. Ha come Proprietà S e O, questo è il motivo per cui è in cima a questi due ed è per questo che c'è un rientro di mezzo carattere. S ha l'apice 170, T ha l'apice 185.

particolarmente duro è anche la parte in cui la parte Str viene spostata di mezzo character.I vorrebbe avere un esempio di questo per integrare nel mio programma.

+3

Inviare a LaTeX o qualche altro composizione/strumento di formattazione sembra la strada da percorrere. Python non viene fornito con una libreria di composizione. –

+0

grazie per la rapida risposta. Ho realizzato il grafic "giusto" con l'illustratore. tuttavia non riesco a far funzionare quella roba anche con latex in questo momento :(aggiornerò una volta che avrò un ulteriore passo. – tarrasch

+0

Questa domanda è limitata ai caratteri mono distanziati? – mmgp

risposta

2

È possibile elaborare soluzioni complicate, considerando i caratteri con spaziatura singola, che potrebbero risolvere il problema. Ma stanno solo aspettando di fallire. Le colonne grigie nel tuo post possono essere aggiunte esattamente come nella tua figura, ma ho scelto di non farlo cambiare i colori nelle lettere (semplicemente perché lo trovo più leggibile in questo modo).

Ecco cosa possibile a venire con PIL:

enter image description here

cambiando leggermente i font:

enter image description here

più "gravi" le modifiche di carattere successivo, tutte prodotte con il codice come è.

enter image description here     enter image description here

E accanto è il codice per la generazione di queste figure. Non l'ho reso davvero carino, e può essere migliorato in molti modi. Consideralo come un esempio di ciò che dovrai fare per, forse, ottenere una soluzione al tuo problema. Per lavorare con qualsiasi tipo di carattere è necessario un sistema di composizione reale, come 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. esattamente quello che stavo cercando. aggiungere più linee come Str sotto? vorrei solo cambiare 'per di, dati in enumerare ([linea1, linea2]):' a per di, dati in enumerare ([linea1, linea2, linex]):? – tarrasch

+0

Sì, sarebbe lavoro, ma devi anche adattare il disegno a 'for k, v in line3_1_top.iteritems(): ...'. Vorrei iniziare aggiungendo un 'num_lines = x' dove' x' è il numero totale di linee che ho scritto, come 4 nel tuo caso e 3 nel mio esempio, e cambio il codice per disegnare gli indici per gestirlo. – mmgp

+0

in realtà non ho bisogno di ripeterlo. Voglio solo aggiungere qualche riga in più nello stesso modo di str. Il tuo codice è al di sopra delle mie capacità :-). Assegnerò la taglia una volta che l'avrò messa al lavoro. Voglio anche ripetere il bit line_3_1 ogni 10 caratteri o giù di lì, come numeri di colonna – tarrasch

1

Questa è davvero più una domanda LaTeX di una domanda Python - cioè, se si determina il markup che si desidera venga generato dallo script Python, allora la sua generazione è abbastanza semplice.

In questo caso, penso che probabilmente potresti ottenere gli effetti desiderati con una tabella abbastanza complessa (\begin{table}...\end{table}), in cui ciascuna delle tue celle occupa due colonne e una colonna viene utilizzata come offset per ottenere il "mezzo carattere" " tu vuoi. Non mi sorprenderebbe se ci fosse un modo più semplice per farlo in LaTeX (che ha molte più librerie di quante ne possa tenere in mente), ma è quello che mi viene in mente. Così il vostro tavolo sarebbe simile a questa:.

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

(Dove + s indicano dove le colonne reali sono, e la maggior parte delle cellule si estendono due colonne La riga con "170" su di esso userebbe \tiny o qualcosa del genere comando.

Il mio suggerimento sarebbe quello di giocare con la generazione di un file LaTeX a mano prima che faccia ciò che si desidera (o qualche altro linguaggio di formattazione del file scelto); e quindi preoccuparsi di scrivere un codice Python per generarlo.

0

Mentre PIL funziona bene per le cose semplici, si hanno molte più opzioni se si utilizza SVG. Puoi usare pySVG (maneggevole pySVG tutorial) o svgwrite per creare il tuo SVG a livello di programmazione, o semplicemente print come testo. Quindi utilizzare ImageMagick (sulla riga di comando come convert o da python utilizzando pythonmagicwand) per rendere SVG a qualsiasi tipo di raster desiderato. Mentre la regolazione fine del SVG è possibile modificare con un editor di testo e vedere le cose in un browser Web :)

# 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') 
Problemi correlati