Root/tools/un-fuzzy.py

1#!/usr/bin/env python
2#
3# This tool depends on the "pygame" package.
4#
5# The Ben NanoNote has a "delta" arrangement of the pixels on its LCD:
6#
7# even rows: R G B|R G B|..
8# odd rows: G B R|G B R|..
9#
10# Note that the odd-numbered rows are shifted 1/6th of pixel width left.
11#
12# A white pixel at (0,1) will appear shifted 1/6th of a pixel left relative to
13# a white pixel at (0,0) resulting in jaggies on vertical lines.
14#
15# This tool processes a sheet of 8x8 font glyphs into a sheet of 4x8 font
16# glyphs using individual green and magenta "pixels" to achieve twice the
17# horizontal resolution. It also compensates for the unusual screen on the
18# NanoNote.
19#
20# NOTE: On the even rows, a single pixel is discarded that would have been made
21# up of the red component of the first column along with the blue component of
22# the last column. On odds rows, the green component of the first column is
23# discarded. This means that last column of the source image is ignored.
24#
25# Example usage:
26#
27# tools/un-fuzzy.py fonts/pre-4x8-font.png /tmp/un-fuzzy-4x8-font.tga
28#
29# Then use GIMP to convert the .tga file to a .pnm file. Imagemagick seems to
30# create P3 .pnm files yet setfont2 can only load P6 .pnm files presently.
31#
32
33import sys
34import pygame
35
36
37# Check and grab the command line arguments
38if len( sys.argv) < 3:
39  print "Use: %s source-image-file target-image-file(BMP|TGA) [grid]" % sys.argv[0]
40  sys.exit( 1)
41
42path_to_source_file = sys.argv[ 1]
43path_to_target_file = sys.argv[ 2]
44grid = ( 4 == len( sys.argv))
45
46# Load the source image and create the target image with the same number of
47# rows but half the number of columns
48source_image = pygame.image.load( path_to_source_file)
49target_image = pygame.Surface( (source_image.get_width()/2, source_image.get_height()))
50
51
52class Colour:
53  def __init__( self):
54    self.red = 0
55    self.green = 0
56    self.blue = 0
57
58  def isnt_black( self):
59    return self.red != 0 or self.green != 0 or self.blue != 0
60
61  def __repr__( self):
62    return "(%i,%i,%i)" % ( self.red, self.green, self.blue)
63
64
65def update_pixel( self, location, colour):
66  current_state = list( self.get_at( location))
67  # NOTE that the new luminances are logical-ORed with the current state of
68  # the pixels since no component should be added to twice, which means that
69  # no overflow of component values should be possible
70  current_state[ 0] |= colour.red
71  current_state[ 1] |= colour.green
72  current_state[ 2] |= colour.blue
73  self.set_at( location, current_state)
74
75
76for row in range( source_image.get_height()):
77  for column in range( source_image.get_width() - 1):
78    pixel = source_image.get_at( (column, row))
79    # "pixel" should be monochrome
80    red = pixel[ 0]
81    green = pixel[ 1]
82    blue = pixel[ 2]
83    if red != green or green != blue:
84      raise Exception("not monochrome at (%i,%i)"%( column, row))
85
86    luminance = red
87
88    # The pixel at ( x, y) in the target image encodes two virtual pixels: one
89    # from the green component and one from the magenta component made by
90    # combining the blue component and the red component of the pixel
91    # immediately to the right of this pixel
92    # For odd-numbered rows the virtual pixels are:
93    # 1) magenta made from blue and red
94    # 2) the green component of the pixel to the right
95
96    # The luminance of the pixel at ( x, y) in the source image is encoded in
97    # different ways depending whether the row is odd or even-numbered and
98    # whether the column is odd or even-numbered
99
100    left = Colour()
101    right = Colour()
102
103    # If preparing SubLCD for a grid-based LCD rather than a Delta LCD..
104    if grid:
105      if 0 == column & 1:
106        # The luminance of this pixel is provided by the green component of the
107        # pixel at ( x, y)
108        left.green = luminance
109      else:
110        # The luminance of this pixel is provided by the magenta component that
111        # is distributed across two pixels ( the blue component of the pixel at
112        # ( x, y) and the red component of the pixel at ( x+1, y))
113        left.blue = luminance
114        right.red = luminance
115    else:
116      # If this row is even-numbered..
117      if 0 == row & 1:
118        # If this column is even-numbered..
119        if 0 == column & 1:
120          # The luminance of this pixel is provided by the green component of the
121          # pixel at ( x, y)
122          left.green = luminance
123        else:
124          # The luminance of this pixel is provided by the magenta component that
125          # is distributed across two pixels ( the blue component of the pixel at
126          # ( x, y) and the red component of the pixel at ( x+1, y))
127          left.blue = luminance
128          right.red = luminance
129      else:
130        if 0 == column & 1:
131          # The luminance of this pixel is provided by the magenta component (
132          # the sum of the red and blue components) of the pixel at ( x, y)
133          left.red = luminance
134          left.blue = luminance
135        else:
136          # The luminance of this pixel is provided by the green component of the
137          # pixel at ( x+1, y)
138          right.green = luminance
139    update_pixel( target_image, (column/2,row), left)
140    #print repr((column,row))
141    #print "L"+repr(left)
142    #print "R"+repr(right)
143    if right.isnt_black():
144      update_pixel( target_image, (column/2+1,row), right)
145
146pygame.image.save( target_image, path_to_target_file)
147
148

Archive Download this file

Branches:
master



interactive