Texas Instrument’s TI-84 Plus is a graphing calculator with a variety of features. It has built-in support for both fractions and complex numbers, can differentiate and integrate given functions and supports programming capabilities. The latter allows to directly manipulate the calculator’s monochrome display’s 5985 pixels (the screen has dimensions 95x63). TImg is a Python program (source code is listed below and can also be downloaded) which takes in an image and outputs TI-BASIC source code which, when run on the graphing calculator, will produce the given image — in potentially lower quality.

TI-84 Plus’ screen dimensions (bitmap).

PIL — the Python Imaging Library — is used to read in the image and further for processing. The supplied image may be rotated and resized to better fit the TI-84’s screen and any color or even grayscale information is reduced to an actual bitmap — every pixel only has two distinct values.
Direct pixel manipulation on the TI-84 is done via the Graph screen. To get remove any pixels the system draws on its own, the first three commands are ClrDraw, GridOff and AxesOff which should result in a completely blank screen — assuming that no functions are currently being drawn. All subsequent commands are in charge of drawing the previously computed bitmap. To turn certain pixels on, Pxl-On(Y,X is used where Y and X are the pixel’s coordinates.

A fractal (bitmap).

Since the TI-84 Plus only has 24 kilobytes of available RAM, the source code for a program which would turn on every single pixel individually does not fit. Luckily, though, a program which only individually turns on half of the screen’s pixels fits. To ensure that TImg’s output fits on the hardware it is designed to be used with, an image’s bitmap is inverted when the required code would otherwise exceed 3500 lines — a value slightly above the required code to draw half of the pixels.

A J-Blog screenshot (bitmap).

By default, the resulting code draws pixels starting at the screen’s top-left corner and ending at its bottom-right. A command line flag --shuffle can be set which changes this behavior to let pixels pseudo-randomly appear on the screen (pseudo-randomness is calculated in the Python script; the TI-BASIC source code is completely deterministic).
And — of course — one can feed the program an image of the calculator the BASIC code runs on; self-referential TIception.

TIception (input image).

# Python 2.7 code; Jonathan Frech; 5th, 6th of October 2017

# import
import sys, random
from PIL import Image

# generate TI-Basic source code which draws the image
def timg(bitmap, crd):
	# generate code
	code = "\n".join(["ClrDraw", "GridOff", "AxesOff"] + ["Pxl-On(%d,%d" % (y, x) for x, y in crd if bitmap[x, y]])
	# code would exceed the calculator's memory; flip all bits
	if len(code) > 3500: bitmap = {c: (not bitmap[c]) for c in crd}; code = "\n".join(["ClrDraw", "GridOff", "AxesOff"] + ["Pxl-On(%d,%d" % (y, x) for x, y in crd if bitmap[x, y]])

	# return code string
	return code

# write error to stderr
def err(msg): sys.stderr.write("\33[38;5;9mError\33[0m: %s\n" % msg); sys.stderr.flush()

# main function
def main():
	# command line file name specification
	if len(sys.argv) < 2: return err("Please specify an input image file name.")

	# open image
	try: img = Image.open(sys.argv[1])
	except: return err("Could not open image.")
	else: img = img.convert("RGB"); w, h = img.size

	# TI-84 Plus screen dimensions
	W, H = 95, 63
	# rotate image if it is higher than wide
	if h > w: img = img.rotate(90, expand = True); w, h = img.size
	# truncate image to maximum dimensions whilst
	# preserving its aspect ratio
	k = 1.*w/h
	if w > W: w = W; h = int(w/k)
	if h > H: h = H; w = int(h*k)
	img = img.resize((w, h))

	# get a list of all image coordinates
	crd = [(x, y) for y in range(h) for x in range(w)]

	# get a list of all pixels
	pix = img.load()

	# list of all pixels; set of all pixels
	pixlst = [pix[c] for c in crd]
	pixset = set(pixlst)

	# too few different pixels
	if len(pixset) == 1: return err("The image only contains one color.")

	# exactly two pixels; use them to truncate
	elif len(pixset) == 2:
		v = min(pixset)
		bitmap = {c: pix[c] == v for c in crd}
	# more than two pixels; take the median as point of truncation (if the list is even, take the left-most element)
		pixsrt = sorted(pixlst)
		v = pixsrt[len(pixsrt)/2]
		bitmap = {c: pix[c] < v for c in crd}

	# shuffle (pixels will be drawn randomly, not top-left to bottom-right)
	if len(sys.argv) > 2 and sys.argv[2] in ["s", "shuffle", "-s", "--shuffle"]: random.shuffle(crd)
	# generate TI-Basic commands to create image
	print timg(bitmap, crd)

# run if main
if __name__ == "__main__": main()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.