adding ascii-art-but-with-unicode

This commit is contained in:
televex 2021-02-24 16:31:03 +00:00
parent 8fde14f8d8
commit 750479d07a
31 changed files with 970 additions and 0 deletions

View File

@ -0,0 +1,2 @@
#!/usr/bin/env python3

View File

@ -0,0 +1,6 @@
#!/usr/bin/env python3
import utils
import patterns
import marks
import text

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
from utils import make_lines, merge, print_lines, rotate, visit, visit_horizontal
from patterns import diagonal, horizontal, vertical, sinus_horizontal, sinus_vertical, image
from marks import random_mark, sequence_mark, space
from random import choice, random
import math
# marks = ['┼', '│', '░', '▓', 'X', '■', '≡', '·', '¦', ' ']
# blank = ' '
width = 75
height = 50
mark = sequence_mark('O.P.E.N D.E.S.I.G.N C.O.U.R.S.E ')
layers = []
# layers.append(visit(make_lines(width, height), image('blobs-small.png'), mark, space(' ')))
for offset in range(-50, 50, 15):
lines = [[] for l in range(height)]
sinus = sinus_vertical(period=50, amplitude=25, offset=offset, offset_t=random())
layers.append(visit(make_lines(width, height), sinus, sequence_mark(' K A S K G E N T '), space()))
for offset in range(-43, 57, 15):
lines = [[] for l in range(height)]
sinus = sinus_vertical(period=40, amplitude=10, offset=offset, offset_t=.5+random())
layers.append(visit(make_lines(width, height), sinus, mark, space()))
print_lines(merge(width, height, space()(), layers))
# for line in overlay(50, 50, ' ', [rotate(merged), merged]):
# stdout.write('{}\n'.format(''.join(line)))
# sinus = sinus_horizontal(period=30, amplitude=8)
# for x in range(width):
# for y in range(height):
# lines[y].append(sinus(x, y, width, height, mark, space()))
# for line in lines:
# stdout.write('{}\n'.format(''.join(line)))
# lines = [[draw(x, y, marks) for x in range(width)] for y in range(height)]
# sys.sdout.write('\n'.join([''.join(line) for line in lines]))
# sys.sdout.write('\n'.join([''.join([draw(x, y, marks) for x in range(width)]) for y in range(height)]))

View File

@ -0,0 +1,24 @@
from random import choice
def random (marks=['']):
def func ():
return choice(marks)
return func
def sentence (text):
chars = list(text)
def f():
char = chars.pop(0)
chars.append(char)
return char
return f
def single (char):
def f():
return char
return f
def space (space=' '):
return single(space)

View File

@ -0,0 +1,67 @@
import math
# # Linear
def diagonal():
def f (x, y, width, height, mark, blank):
if x == math.floor((y / float(height)) * width):
return mark()
else:
return blank()
return f
# Cross
def cross ():
def f (x, y, width, height, mark, blank):
pos = math.floor((y / float(height)) * width)
if x == pos or (width - 1) - pos == x:
return mark()
else:
return blank()
return f
def horizontal (position):
def f (x, y, width, height, mark, blank):
return mark() if position == y else blank()
return f
def vertical (position):
def f (x, y, width, height, mark, blank):
return mark() if position == x else blank()
return f
# Sinus
def sinus_vertical (period=0.2, amplitude=0.5, offset_t=0, offset=0):
period = (period / (math.pi * 2))
def f (x, y, width, height, mark, blank):
middle = (width - 1) * .5
to_mark = math.floor(middle + math.sin(offset_t + y / period) * amplitude)
return mark() if (x + offset) == to_mark else blank()
return f
def sinus_horizontal (period=0.2, amplitude=0.5, offset_t=0, offset=0):
period = (period / (math.pi * 2))
def f (x, y, width, height, mark, blank):
middle = (height - 1) * .5
to_mark = math.floor(middle + math.sin(offset_t + x / period) * amplitude)
return mark() if y + offset == to_mark else blank()
return f
def image (path, threshold=128):
from PIL import Image
im = Image.open(path).convert('L')
image_width, image_height = im.size
pixels = im.load()
def f (x, y, width, height, mark, blank):
if x < image_width and y < image_height:
if pixels[x, y] < threshold:
return mark()
return blank()
return f

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from .wrap_single_line import wrap_single_line
from .utils import translate, merge
def make_column(text, line_width=50, height=200, use_hyphenator=None, line_offset=0):
lines = []
remaining = text
while remaining and len(lines) < height:
if callable(line_width):
width = line_width(len(lines), height)
else:
width = line_width
if callable(line_offset):
offset = line_offset(len(lines), height)
else:
offset = line_offset
line, remaining = wrap_single_line(remaining, width, use_hyphenator=use_hyphenator, replace_whitespace=False, drop_whitespace=True)
line = list(line)
if offset != 0:
line = [None for _ in range(offset)] + line
lines.append(line)
return lines, remaining
def make_multi_column(text, height=200, column_width=40, column_count=2, column_gap=5, use_hyphenator=None, space_char=None):
# todo: vertical offset?
remaining = text
i = 0
columns = []
while remaining and i < column_count:
column, remaining = make_column(remaining, line_width=column_width, height=height, use_hyphenator=use_hyphenator)
if i > 0:
offset = (column_width + column_gap) * i
column = translate(column, x=offset, y=0)
columns.append(column)
i += 1
width = (column_width + column_gap) * column_count
lines = merge(width, height, space_char, columns)
return lines, remaining
if __name__ == '__main__':
print(make_column('Hello world!', line_width=25, height=10))

View File

@ -0,0 +1,61 @@
from sys import stdout
def rotate(layer):
new_width = len(layer)
new_height = len(layer[0])
rotated = [['' for x in range(new_width)] for l in range(new_height)]
for y in range(len(layer)):
for x in range(len(layer[y])):
rotated[x][y] = layer[y][x]
return rotated
def merge(width, height, space_char, layers):
output = [[space_char for x in range(width)] for y in range(height)]
for layer in layers:
for y in range(min(len(layer), height)):
for x in range(min(len(layer[y]), width)):
if layer[y][x] and layer[y][x] != space_char:
output[y][x] = layer[y][x]
return output
# Make a multidimensional array
# with the given dimensions
def make_lines (width, height, fill_char = ''):
return [[ fill_char for _ in range(width) ] for __ in range(height)]
def visit (lines, callback, mark, blank):
height = len(lines)
width = len(lines[0])
for y in range(height):
for x in range(width):
lines[y][x] = callback(x, y, width, height, mark, blank)
return lines
def visit_horizontal (lines, callback, mark, blank):
height = len(lines)
width = len(lines[0])
for x in range(width):
for y in range(height):
lines[y][x] = callback(x, y, width, height, mark, blank)
return lines
def print_lines (lines):
for line in lines:
stdout.write('{}\n'.format(''.join(line)))
def translate(shape, x=0, y=0):
## TODO implement a negative translation?
translated = [[] for _ in range(y)]
for line in shape:
translated.append([None for _ in range(x)] + line)
return translated

View File

@ -0,0 +1,137 @@
"""
Based on the textwrap2 module included in the PyHyphen library:
https://pypi.org/project/PyHyphen
"""
import textwrap
class TextWrapper(textwrap.TextWrapper):
"""
This class extends the Python 3 standard library's TextWrapper and adds an optional
use_hyphenator to its constructor arguments.
"""
def __init__(self, *args, **kwargs):
self.use_hyphenator = kwargs.pop("use_hyphenator", None)
super().__init__(*args, **kwargs)
def _wrap_chunks(self, chunks):
lines = []
if (chunks):
"""Override the mother class method.
Most of that method is directly copied from the original class, except
for the part with use_hyphenator.
"""
if self.width <= 0:
raise ValueError("invalid width %r (must be > 0)" % self.width)
if self.max_lines is not None:
if self.max_lines > 1:
indent = self.subsequent_indent
else:
indent = self.initial_indent
if len(indent) + len(self.placeholder.lstrip()) > self.width:
raise ValueError("placeholder too large for max width")
# Arrange in reverse order so items can be efficiently popped
# from a stack of chucks.
chunks.reverse()
# Start the list of chunks that will make up the current line.
# cur_len is just the length of all the chunks in cur_line.
cur_line = []
cur_len = 0
# Figure out which static string will prefix this line.
if lines:
indent = self.subsequent_indent
else:
indent = self.initial_indent
# Maximum width for this line.
width = self.width - len(indent)
# First chunk on line is whitespace -- drop it, unless this
# is the very beginning of the text (ie. no lines started yet).
if self.drop_whitespace and chunks[-1].strip() == '' and chunks[-1][0] != '\n': # and lines:
del chunks[-1]
while chunks:
l = len(chunks[-1])
# Check for a newline character
if chunks[-1] == '\n':
return indent + ''.join(cur_line), ''.join(reversed(chunks[:-1]))
elif chunks[-1][0] == '\n':
return indent + ''.join(cur_line), ''.join(reversed(chunks[:-1] + [chunks[-1][1:]]))
# Can at least squeeze this chunk onto the current line.
if cur_len + l <= width:
cur_line.append(chunks.pop())
cur_len += l
# Nope, this line is full.
# But try hyphenation.
else:
if self.use_hyphenator and (width - cur_len >= 2):
hyphenated_chunk = self.use_hyphenator.wrap(chunks[-1], width - cur_len)
if hyphenated_chunk:
cur_line.append(hyphenated_chunk[0])
chunks[-1] = hyphenated_chunk[1]
break
# The current line is full, and the next chunk is too big to
# fit on *any* line (not just this one).
if chunks and len(chunks[-1]) > width:
self._handle_long_word(chunks, cur_line, cur_len, width)
cur_len = sum(map(len, cur_line))
# If the last chunk on this line is all whitespace, drop it.
if self.drop_whitespace and cur_line and cur_line[-1].strip() == '':
cur_len -= len(cur_line[-1])
del cur_line[-1]
if cur_line:
if (self.max_lines is None or
len(lines) + 1 < self.max_lines or
(not chunks or
self.drop_whitespace and
len(chunks) == 1 and
not chunks[0].strip()) and cur_len <= width):
# Convert current line back to a string and store it in
# list of all lines (return value).
return indent + ''.join(cur_line), ''.join(reversed(chunks))
else:
while cur_line:
if (cur_line[-1].strip() and
cur_len + len(self.placeholder) <= width):
cur_line.append(self.placeholder)
return indent + ''.join(cur_line), ''.join(reversed(chunks))
cur_len -= len(cur_line[-1])
del cur_line[-1]
else:
if lines:
prev_line = lines[-1].rstrip()
if (len(prev_line) + len(self.placeholder) <=
self.width):
lines[-1] = prev_line + self.placeholder
return indent + self.placeholder.lstrip(), ''.join(reversed(chunks))
else:
return '', ''
def wrap_single_line (text, width=70, **kwargs):
w = TextWrapper(width=width, **kwargs)
return w.wrap(text)
if __name__ == '__main__':
from hyphen import Hyphenator
h_en = Hyphenator('en_US')
line, remaining = wrap_single_line('https://stackoverflow.com/questions/3940128/how-can-i-reverse-a-list-in-python', width=46, use_hyphenator=h_en)
print(line, remaining)

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
Uses an image as a guide to draw either blanks or
mark chars. In this case with the char '+'.
"""
from asciiWriter.patterns import image
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import single, space
width = 75
height = 75
# Where to find the image
image_path = 'images/blobs-small.png'
# Construct the pattern
image_pattern = image(image_path)
# Set the marker, in this case the character '+'
mark = single('+')
# Define what to use on a blank space, as a variation you could use: single('*')
blank = space()
# Make a canvas
lines = make_lines(width, height)
# Draw the picture
result = visit(lines, image_pattern, mark, blank)
# Print the result
print_lines(result)

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
from asciiWriter.patterns import image
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import random, single
width = 75
height = 75
# Where to find the image
image_path = 'images/blobs-small.png'
# Construct the pattern
image_pattern = image(image_path)
# Set the marker, in this case it makes a random selection from
# the list: +, *, $, #, ,
mark = random(['+', '*', '$', '#', ' ', ' '])
# Define what to use on a blank space, as a variation you coul use: single('*')
blank = single()
# Make a canvas
lines = make_lines(width, height)
# Draw the picture
result = visit(lines, image_pattern, mark, blank)
# Print the result
print_lines(result)

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
Same as image_sentence.py, but rotates the result.
Uses an image to define where to put chars.
In this case with the sentence/word ASCII
"""
from asciiWriter.patterns import image
from asciiWriter.utils import make_lines, visit, print_lines, rotate
from asciiWriter.marks import sentence, single
width = 75
height = 75
# Where to find the image
image_path = 'images/blobs-small.png'
# Construct the pattern
image_pattern = image(image_path)
# Set the marker, in this case a sentence
mark = sentence('ASCII ')
# Define what to use on a blank space, as a variation you coul use: single('*')
blank = single(' ')
# Make a canvas
lines = make_lines(width, height)
# Draw the picture
result = visit(lines, image_pattern, mark, blank)
# Rotate the canvas
result = rotate(result)
# Print the result
print_lines(result)

View File

@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""
Uses an image to define where to put chars.
In this case with the sentence/word ASCII
"""
from asciiWriter.patterns import image
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import sentence, space
width = 75
height = 75
# Where to find the image
image_path = 'images/blobs-small.png'
image_path = 'images/shapes.png'
# Construct the pattern
image_pattern = image(image_path)
# Set the marker, in this case a sentence
mark = sentence('U.R.S O.P.E.N. D.E.S.I.G.N C.O.')
# Define what to use on a blank space, as a variation you coul use: single('*')
blank = space()
# Make a canvas
lines = make_lines(width, height)
# Draw the picture
result = visit(lines, image_pattern, mark, blank)
# Print the result
print_lines(result)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""
Draws a single, vertical line
"""
from asciiWriter.patterns import vertical
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import sentence, space
# Set the canvas
width = 75
height = 75
# Define the line, most importantly it's position
pattern = vertical(20)
# We're going to fill the line with a text
mark = sentence('OPEN DESIGN COURSE ')
# Set the character for the 'blank' space
blank = space()
# Make a canvas
lines = make_lines(width, height)
# Draw the result
result = visit(lines, pattern, mark, blank)
# Print the result
print_lines(result)

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
Draws a single just like line.py but does so
using a 'random' character
"""
from asciiWriter.patterns import vertical
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import random, space
# Set the canvas
width = 75
height = 75
# Define the line, most importantly it's position
image_pattern = vertical(20)
# We're going to fill the line with random selections
# from the '%$&@!*' chars
mark = random('%$&@!*')
# Set the character for the 'blank' space
blank = space()
# Make a canvas
lines = make_lines(width, height)
# Draw the result
result = visit(lines, image_pattern, mark, blank)
# Print the result
print_lines(result)

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python3
from asciiWriter.text import make_column, make_multi_column
from asciiWriter.utils import merge, print_lines, make_lines, translate
import math
# Define width and height of the output
width = 125
height = 27
# Import a text
text = open('texts/about.txt').read()
# Make an empty layers list
layers = []
def sin_width (line_nr, _):
amplitude = 25
period = 150 / (math.pi * 2)
return 50 + math.floor(math.sin(line_nr / period) * amplitude)
def cos_width (line_nr, _):
amplitude = 5
period = 20 / (math.pi * 2)
half_amplitude = amplitude * .5
return math.floor(half_amplitude + math.cos(line_nr / period) * half_amplitude)
# Transform the text into a single column
#lines, remaining = make_column(text, height=height, line_width=sin_width, line_offset=cos_width)
# Transform the text into multiple columns
lines, remaining = make_multi_column(text, height=height, column_width=40, column_count=2, column_gap=5)
lines = translate(lines, x=20, y=0)
# Create an background
background = make_lines(width, height, ' ')
# Add all your layers to the layers list
layers.append(background)
layers.append(lines)
# Merge the layers into one layer again
merged = merge(width, height, ' ', layers)
# Print the result
print_lines(merged)

View File

@ -0,0 +1,61 @@
# ASCII-ART-BUT-WITH-UNICODE
<pre>
---------H---------H---------H---------H---------H---------H---------H---------H---------H---------H
-------------------e------e-------e------e-------e-------e------e-------e------e-------e------------
----------------------------l----l-----l----l----l----l----l-----l----l----l------------------------
------------------------------------l---l--l--l--l--l--l--l---l--l----------------------------------
-------------------------------------------oo-oo-o-oo-oo-o------------------------------------------
----------------------------------------------- ------------------------------------------------
-------------------------------------------------W--------------------------------------------------
------------------------------------------------ooo-------------------------------------------------
---------------------------------------------rrrrrrrrrr---------------------------------------------
----------------------------------------l-l-l--l-l-l--l-l-l-l---------------------------------------
---------------------------------d---d---d---d---d---d---d---d---d----d-----------------------------
------------------------!-----!-----!------!-----!-----!------!-----!-----!------!------------------
-------------- -------- -------- ------- -------- -------- ------- -------- -------- -------- ------
----H----------H----------H-----------H----------H----------H-----------H----------H----------H-----
--------e-------------e------------e-------------e-------------e------------e-------------e---------
-l---------------l---------------l---------------l---------------l---------------l---------------l--
--------------l----------------l-----------------l-----------------l----------------l---------------
-----------o------------------o------------------o------------------o------------------o------------
--------- ------------------- ------------------- ------------------- ------------------- ----------
---------W-------------------W-------------------W-------------------W-------------------W----------
----------o------------------o-------------------o-------------------o------------------o-----------
------------r------------------r-----------------r-----------------r------------------r-------------
---------------l----------------l----------------l----------------l----------------l----------------
-----l-------------d--------------d--------------d--------------d--------------d-------------l------
------------o-----------!------------!-----------!-----------!------------!-----------o------------e
---------e--------- --------- --------- --------- --------- --------- --------- ---------l---------H
-------------------l------W-------H------H-------H-------H------H-------W------l-------e------------
----------------------------l----o-----e----e----e----e----e-----o----o----l------------------------
------------------------------------o---r--l--l--l--l--l--r--- --l----------------------------------
------------------------------------------- l-ll-l-ll-lW-o------------------------------------------
-----------------------------------------------Wdooo------------------------------------------------
-------------------------------------------------o--------------------------------------------------
------------------------------------------------rW -------------------------------------------------
---------------------------------------------lHoooooHdr---------------------------------------------
----------------------------------------d-e-r--r-r-r--r-e-!-l---------------------------------------
---------------------------------!---l---l---l---l---l---l---l--- ----d-----------------------------
------------------------ -----l-----d------d-----d-----d------d-----l-----H------!------------------
--------------H--------o--------!-------!--------!--------!-------!--------o--------e-------- ------
----e---------- ---------- ----------- ---------- ---------- ----------- ---------- ----------l-----
--------W-------------H------------H-------------H-------------H------------H-------------W---------
-o---------------e---------------e---------------e---------------e---------------e---------------o--
--------------l----------------l-----------------l-----------------l----------------l---------------
-----------l------------------l------------------l------------------l------------------l------------
---------o-------------------o-------------------o-------------------o-------------------o----------
--------- ------------------- ------------------- ------------------- ------------------- ----------
----------W------------------W-------------------W-------------------W------------------W-----------
------------o------------------o-----------------o-----------------o------------------o-------------
---------------r----------------r----------------r----------------r----------------r----------------
-----r-------------l--------------l--------------l--------------l--------------l-------------r------
------------l-----------d------------d-----------d-----------d------------d-----------l------------l
</pre>
Work in progress :)
# Requirements
* pillow
* pyhyphen

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
Draws lines like line.py, but draws more than one
"""
from asciiWriter.patterns import vertical
from asciiWriter.utils import make_lines, visit, print_lines, merge
from asciiWriter.marks import sentence, space
# Set the canvas
width = 75
height = 75
# We are going to draw multiple lines and collect them
# in a list named 'layers'
layers = []
# Set the position of the line, do this in a loop
# from 10 to 75 in steps of then
for x in range(10, 75, 10):
# Define the line, x will start at 10 and grow in steps of 10
image_pattern = vertical(x)
# Fill the line with the sentence 'OPEN DESIGN COURSE '
mark = sentence('OPEN DESIGN COURSE ')
# Set the blank space
blank = space()
# Make a canvas
lines = make_lines(width, height)
# Make a layer with the line
layer = visit(lines, image_pattern, mark, blank)
# Add the layer to the list of layers
layers.append(layer)
# Merge the list of layers into a single layer
result = merge(width, height, blank(), layers)
# Print the result
print_lines(result)

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
from asciiWriter.patterns import sinus_vertical
from asciiWriter.utils import make_lines, visit, print_lines, merge
from asciiWriter.marks import sentence, space
# Define width and height of the output
width = 75
height = 75
# As we draw multiple sinoids we will collect
# them in a list of layers
layers = []
# Loop through an offset from -40 to 40 in steps of 10
for x in range(-40, 40, 10):
# Set the pattern with the changing offset
pattern = sinus_vertical(period=40, amplitude=30, offset=x)
# We use a sentence to draw the text
mark = sentence('OPEN DESIGN COURSE ')
# Define a blank character
blank = space()
# Make the canvas
lines = make_lines(width, height)
# Draw the sinoid, but add it to the list
result = visit(lines, pattern, mark, blank)
# Add it the result to the list of layers
layers.append(result)
# Merge the layers into one layer again
merged = merge(width, height, blank(), layers)
# Print the result
print_lines(merged)

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
from asciiWriter.patterns import sinus_vertical
from asciiWriter.utils import make_lines, visit, print_lines, merge, translate
from asciiWriter.marks import sentence, space
import random
# Define width and height of the output
width = 125
height = 90
# As we draw multiple sinoids we will collect
# them in a list of layers
layers = []
# Loop through an amplitude of -50 to 50 in steps of 10
for amplitude in range(-40, 50, 10):
# Set the pattern with the changing amplitude
pattern = sinus_vertical(period=60, amplitude=amplitude)
# We use a sentence to draw the text
mark = sentence('VARIA-')
# Define a blank character
blank = space('-')
# Make the canvas
lines = make_lines(width, height)
# Draw the sinoid, but add it to the list
result = visit(lines, pattern, mark, blank)
# Add it the result to the list of layers
layers.append(result)
# Merge the layers into one layer again
merged = merge(width, height, blank(), layers)
# Print the result
print_lines(merged)

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
from asciiWriter.text import make_column, make_multi_column
from asciiWriter.utils import merge, print_lines, make_lines, translate
from hyphen import Hyphenator
import math
# Define width and height of the output
width = 100
height = 500
# Import a text
text = open('texts/language.txt').read()
# Import a hyphenator
h_en = Hyphenator('en_US')
# Make an empty layers list
layers = []
def sin_width (line_nr, _):
amplitude = 25
period = 150 / (math.pi * 2)
return 50 + math.floor(math.sin(line_nr / period) * amplitude)
def cos_width (line_nr, _):
amplitude = 5
period = 20 / (math.pi * 2)
half_amplitude = amplitude * .5
return math.floor(half_amplitude + math.cos(line_nr / period) * half_amplitude)
# Transform the text into a column
lines, remaining = make_column(text, height=height, use_hyphenator=h_en, line_width=sin_width, line_offset=cos_width)
# Transform the text into multiple columns
# lines, remaining = make_multi_column(text, height=height-3, use_hyphenator=h_en)
lines = translate(lines, x=15, y=1)
# Create an background
background = make_lines(width, height, ' ')
# Add all your layers to the layers list
layers.append(background)
layers.append(lines)
# Merge the layers into one layer again
merged = merge(width, height, ' ', layers)
# Print the result
print_lines(merged)

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
from asciiWriter.patterns import sinus_vertical
from asciiWriter.utils import make_lines, visit, print_lines
from asciiWriter.marks import sentence, space, single
# Define width and height of the output
width = 75
height = 75
# Set the pattern we use to draw, in this case a
# sinoid, with period of 40 lines, and an amplitude
# of 30 characters. Slightly less than half our canvas width
pattern = sinus_vertical(period=40, amplitude=30)
# We use a sentence to draw the text
mark = sentence('OPEN DESIGN COURSE ')
# Define a blank character
blank = single(' ')
# Make the canvas
lines = make_lines(width, height)
# Draw the sinoid
result = visit(lines, pattern, mark, blank)
# Output the result
print_lines(result)

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
from asciiWriter.patterns import sinus_vertical, cross
from asciiWriter.utils import make_lines, visit, print_lines, merge
from asciiWriter.marks import sentence, space, single
# Define width and height of the output
width = 100
height = 50
# As we draw multiple sinoids we will collect
# them in a list of layers
layers = []
# Loop through an offset from -40 to 40 in steps of 10
for x in range(-50, 50, 10):
# Set the pattern with the changing offset
pattern = cross()
# We use a sentence to draw the text
mark = sentence('Hello World! ')
# Define a blank character
blank = single('-')
# Make the canvas
lines = make_lines(width, height)
# Draw the sinoid, but add it to the list
result = visit(lines, pattern, mark, blank)
# Add it the result to the list of layers
layers.append(result)
# Merge the layers into one layer again
merged = merge(width, height, blank(), layers)
# Print the result
print_lines(merged)

View File

@ -0,0 +1,55 @@
Language
Florian Cramer
Software and language are intrinsically related, since software may process language, and is constructed in language. Yet language means different things in the context of computing: formal languages in which algorithms are expressed and software is implemented, and in so-called “natural” spoken languages.
There are at least two layers of formal language in software: programming language in which the software is written, and the language implemented within the software as its symbolic controls. In the case of compilers, shells, and macro languages, for example, these layers can overlap. “Natural” language is what can be processed as data by software; since this processing is formal, however, it is restricted to syntactical operations.
While differentiation of computer programming languages as “artificial languages” from languages like English as “natural languages” is conceptually important and undisputed, it remains problematic in its pure terminology: There is nothing “natural” about spoken language; it is a cultural construct and thus just as “artificial” as any formal machine control language. To call programming languages “machine languages” doesnt solve the problem either, as it obscures that “machine languages” are human creations.
High-level machine-independent programming languages such as Fortran, C, Java, and Basic are not even direct mappings of machine logic. If programming languages are human languages for machine control, they could be called cybernetic languages. But these languages can also be used outside machines—in programming handbooks, for example, in programmers dinner table jokes, or as abstract formal languages for expressing logical constructs, such as in Hugh Kenners use of the Pascal programming language to explain aspects of the structure of Samuel Becketts writing.1
In this sense, computer control languages could be more broadly defined as syntactical languages as opposed to semantic languages. But this terminology is not without its problems either. Common languages like English are both formal and semantic; although their scope extends beyond the formal, anything that can be expressed in a computer control language can also be expressed in common language. It follows that computer control languages are a formal (and as such rather primitive) subset of common human languages.
To complicate things even further, computer science has its own understanding of “operational semantics” in programming languages, for example in the construction of a programming language interpreter or compiler. Just as this interpreter doesnt perform “interpretations” in a hermeneutic sense of semantic text explication, the computer science notion of “semantics” defies linguistic and common sense understanding of the word, since compiler construction is purely syntactical, and programming languages denote nothing but syntactical manipulations of symbols.
What might more suitably be called the semantics of computer control languages resides in the symbols with which those operations are denoted in most programming languages: English words like “if,” “then,” “else,” “for,” “while,” “goto,” and “print,” in conjunction with arithmetical and punctuation symbols; in alphabetic software controls, words like “list,” “move,” “copy,” and “paste”; in graphical software controls, such as symbols like the trash can.
Ferdinand de Saussure states that the signs of common human language are arbitrary2 because its purely a cultural-social convention that assigns phonemes to concepts. Likewise, its purely a cultural convention to assign symbols to machine operations. But just as the cultural choice of phonemes in spoken language is restrained by what the human voice can pronounce, the assignment of symbols to machine operations is limited to what can be efficiently processed by the machine and of good use to humans.3 This compromise between operability and usability is obvious in, for example, Unix commands. Originally used on teletype terminals, the operation “copy” was abbreviated to the command “cp,” “move” to “mv,” “list” to “ls,” etc., in order to cut down machine memory use, teletype paper consumption, and human typing effort at the same time. Any computer control language is thus a cultural compromise between the constraints of machine design—which is far from objective, but based on human choices, culture, and thinking style itself 4—and the equally subjective user preferences, involving fuzzy factors like readability, elegance, and usage efficiency.
The symbols of computer control languages inevitably do have semantic connotations simply because there exist no symbols with which humans would not associate some meaning. But symbols cant denote any semantic statements, that is, they do not express meaning in their own terms; humans metaphorically read meaning into them through associations they make. Languages without semantic denotation are not historically new phenomena; mathematical formulas are their oldest example.
In comparison to common human languages, the multitude of programming languages is of lesser significance. The criterion of Turing completeness of a programming language, that is, that any computation can be expressed in it, means that every programming language is, formally speaking, just a riff on every other programming language. Nothing can be expressed in a Turingcomplete language such as C that couldnt also be expressed in another Turingcomplete language such as Lisp (or Fortran, Smalltalk, Java . . .) and vice versa.
This ultimately proves the importance of human and cultural factors in programming languages: while they are interchangeable in regard to their control of machine functions, their different structures—semantic descriptors, grammar and style in which algorithms can be expressed—lend themselves not only to different problem sets, but also to different styles of thinking.
Just as programming languages are a subset of common languages, Turingincomplete computer control languages are a constrained subset of Turingcomplete languages. This prominently includes markup languages (such as HTML), file formats, network protocols, and most user controls (see the entry “Interface”) of computer programs. In most cases, languages of this type are restrained from denoting algorithmic operations for computer security reasons—to prevent virus infection and remote takeover. This shows how the very design of a formal language is a design for machine control. Access to hardware functions is limited not only through the software application, but through the syntax the software application may use for storing and transmitting the information it processes. To name one computer control language a “programming language,” another a “protocol,” and yet another a “file format” is merely a convention, a nomenclature indicating different degrees of syntactic restraint built into the very design of a computer control language.
In its most powerful Turing-complete superset, computer control language is language that executes. As with magical and speculative concepts of language, the word automatically performs the operation. Yet this is not to be confused with what linguistics calls a “performative” or “illocutionary” speech act, for example, the words of a judge who pronounces a verdict, a leader giving a command, or a legislator passing a law. The execution of computer control languages is purely formal; it is the manipulation of a machine, not a social performance based on human conventions such as accepting a verdict. Computer languages become performative only through the social impact of the processes they trigger, especially when their outputs arent critically checked.
Joseph Weizenbaums software psychotherapist Eliza, a simple program that syntactically transforms input phrases, is a classical example,5 as is the 1987 New York Stock Exchange crash that involved a chain reaction of “sell” recommendations by day trading software.6 Writing in a computer programming language is phrasing instructions for an utter idiot. The project of Artificial Intelligence is to prove that intelligence is just a matter of a sufficiently massive layering of foolproof recipes—in linguistic terms, that semantics is nothing else but (more elaborate) syntax. As long as A.I. fails to deliver this proof, the difference between common languages and computer control languages continues to exist, and language processing through computers remains restrained to formal string manipulations, a fact that after initial enthusiasm has made many experimental poets since the 1950s abandon their experiments with computer-generated texts.7
The history of computing is rich with confusions of formal with common human languages, and false hopes and promises that formal languages would become more like common human languages. Among the unrealized hopes are artificial intelligence, graphical user interface design with its promise of an “intuitive” or, to use Jef Raskins term, “humane interface,”8 and major currents of digital art. Digital installation art typically misperceives its programmed behaviorist black boxes as “interactive,” and some digital artists are caught in the misconception that they can overcome what they see as the Western male binarism of computer languages by reshaping them after romanticized images of indigenous human languages. The digital computer is a symbolic machine that computes syntactical language and processes alphanumerical symbols; it treats all data—including images and sounds—as textual, that is, as chunks of coded symbols. Nelson Goodmans criteria of writing as “disjunct” and “discrete,” or consisting of separate single entities that differ from other separate single entities, also applies to digital files.9 The very meaning of “digitization” is to structure analog data as numbers and store them as numerical texts composed of discrete parts.
All computer software controls are linguistic regardless of their perceivable shape, alphanumerical writing, graphics, sound signals, or whatever else. The Unix command “rm file” is operationally identical to dragging the file into the trashcan on a desktop. Both are just different encodings for the same operation, just as alphabetic language and morse beeps are different encodings for the same characters. As a symbolic handle, this encoding may enable or restrain certain uses of the language. In this respect, the differences between ideographic-pictorial and abstract-symbolic common languages also apply to computer control languages. Pictorial symbols simplify control languages through predefined objects and operations, but make it more difficult to link them through a grammar and thus express custom operations. Just as a pictogram of a house is easier to understand than the letters h-o-u-s-e, the same is true for the trashcan icon in comparison to the “rm” command. But it is difficult to precisely express the operation “If I am home tomorrow at six, I will clean up every second room in the house” through a series of pictograms. Abstract, grammatical alphanumeric languages are more suitable for complex computational instructions.10 The utopia of a universal pictorial computer control language (with icons, windows, and pointer operations) is a reenactment of the rise and eventual fall of universal pictorial language utopias in the Renaissance, from Tommaso Campanellas “Città del sole” to Comenius “Orbis pictus”—although the modern project of expressing only machine operations in pictograms was less ambitious.
The converse to utopian language designs occurs when computer control languages get appropriated and used informally in everyday culture. Jonathan Swift tells how scientists on the flying island of Lagado “would, for example, praise the beauty of a woman, or any other animal . . . by rhombs, circles, parallelograms, ellipses, and other “geometrical terms.” 11 Likewise, there is programming language poetry which, unlike most algorithmic poetry, writes its program source as the poetical work, or crossbreeds cybernetic with common human languages. These “code poems” or “codeworks” often play with the interference between human agency and programmed processes in computer networks.
In computer programming and computer science, “code” is often understood either as a synonym of computer programming language or as a text written in such a language. This modern usage of the term “code” differs from the traditional mathematical and cryptographic notion of code as a set of formal transformation rules that transcribe one group of symbols to another group of symbols, for example, written letters into morse beeps. The translation that occurs when a text in a programming language gets compiled into machine instructions is not an encoding in this sense because the process is not oneto-one reversible. This is why proprietary software companies can keep their source “code” secret. It is likely that the computer cultural understanding of “code” is historically derived from the name of the first high-level computer programming language, “Short Code” from 1950.12 The only programming language that is a code in the original sense is assembly language, the human-readable mnemonic one-to-one representation of processor instructions. Conversely, those instructions can be coded back, or “disassembled,” into assembly language.
Software as a whole is not only “code” but a symbolic form involving cultural practices of its employment and appropriation. But since writing in a computer control language is what materially makes up software, critical thinking about computers is not possible without an informed understanding of the structural formalism of its control languages. Artists and activists since the French Oulipo poets and the MIT hackers in the 1960s have shown how their limitations can be embraced as creative challenges. Likewise, it is incumbent upon critics to reflect the sometimes more and sometimes less amusing constraints and game rules computer control languages write into culture.
Notes
1. Hugh Kenner, “Beckett Thinking,” in Hugh Kenner, The Mechanic Muse, 83107.
2. Ferdinand de Saussure, Course in General Linguistics, ”Chapter I: Nature of the Linguistic Sign.”
3. See the section, “Saussurean Signs and Material Matters,” in N. Katherine Hayles, My Mother Was a Computer, 4245.
4. For example, Steve Wozniaks design of the Apple I mainboard was considered “a beautiful work of art” in its time according to Steven Levy, Insanely Great: The Life and
Times of Macintosh, 81.
5. Joseph Weizenbaum, “ELIZA—A Computer Program for the Study of Natural Language Communication between Man and Machine.”
6. Marsha Pascual, “Black Monday, Causes and Effects.”
7. Among them concrete poetry writers, French Oulipo poets, the German poet Hans Magnus Enzensberger, and the Austrian poets Ferdinand Schmatz and Franz Josef Czernin.
8. Jef Raskin, The Humane Interface: New Directions for Designing Interactive Systems.
9. According to Nelson Goodmans definition of writing in The Languages of Art, 143.
10. Alan Kay, an inventor of the graphical user interface, conceded in 1990 that “it would not be surprising if the visual system were less able in this area than the mechanism that solve noun phrases for natural language. Although it is not fair to say that iconic languages cant work just because no one has been able to design a good one, it is likely that the above explanation is close to truth.” This status quo hasnt changed since. Alan Kay, “User Interface: A Personal View,” in, Brenda Laurel ed. The Art of Human-Computer Interface Design, Reading: Addison Wesley, 1989, 203.
11. Swift, Jonathan, Gullivers Travels, Project Gutenberg Ebook, available at http: // www.gutenberg.org / dirs / extext197 / gltrv10.txt / .
12. See Wolfgang Hagen, “The Style of Source Codes.”