1
#Copyright ReportLab Europe Ltd. 2000-2004
2
#see license.txt for license details
3
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/lib/codecharts.py
5
__version__=''' $Id '''
6
__doc__="""Routines to print code page (character set) drawings.
8
To be sure we can accurately represent characters in various encodings
9
and fonts, we need some routines to display all those characters.
10
These are defined herein. The idea is to include flowable, drawable
11
and graphic objects for single and multi-byte fonts. """
14
from reportlab.pdfgen.canvas import Canvas
15
from reportlab.platypus import Flowable
16
from reportlab.pdfbase import pdfmetrics, cidfonts
17
from reportlab.graphics.shapes import Drawing, Group, String, Circle, Rect
18
from reportlab.graphics.widgetbase import Widget
19
from reportlab.lib import colors
22
class CodeChartBase(Flowable):
23
"""Basic bits of drawing furniture used by
24
single and multi-byte versions: ability to put letters
28
"Work out x and y positions for drawing"
31
rows = self.codePoints * 1.0 / self.charsPerRow
35
self.rows = int(rows) + 1
36
# size allows for a gray column of labels
37
self.width = self.boxSize * (1+self.charsPerRow)
38
self.height = self.boxSize * (1+self.rows)
42
for row in range(self.rows + 2):
43
self.ylist.append(row * self.boxSize)
45
for col in range(self.charsPerRow + 2):
46
self.xlist.append(col * self.boxSize)
48
def formatByte(self, byt):
54
def drawChars(self, charList):
55
"""Fills boxes in order. None means skip a box.
56
Empty boxes at end get filled with gray"""
57
extraNeeded = (self.rows * self.charsPerRow - len(charList))
58
for i in range(extraNeeded):
60
#charList.extend([None] * extraNeeded)
63
self.canv.setFont(self.fontName, self.boxSize * 0.75)
64
for ch in charList: # may be 2 bytes or 1
66
self.canv.setFillGray(0.9)
67
self.canv.rect((1+col) * self.boxSize, (self.rows - row - 1) * self.boxSize,
68
self.boxSize, self.boxSize, stroke=0, fill=1)
69
self.canv.setFillGray(0.0)
72
self.canv.drawCentredString(
73
(col+1.5) * self.boxSize,
74
(self.rows - row - 0.875) * self.boxSize,
78
self.canv.setFillGray(0.9)
79
self.canv.rect((1+col) * self.boxSize, (self.rows - row - 1) * self.boxSize,
80
self.boxSize, self.boxSize, stroke=0, fill=1)
81
self.canv.drawCentredString(
82
(col+1.5) * self.boxSize,
83
(self.rows - row - 0.875) * self.boxSize,
86
self.canv.setFillGray(0.0)
88
if col == self.charsPerRow:
92
def drawLabels(self, topLeft = ''):
93
"""Writes little labels in the top row and first column"""
94
self.canv.setFillGray(0.8)
95
self.canv.rect(0, self.ylist[-2], self.width, self.boxSize, fill=1, stroke=0)
96
self.canv.rect(0, 0, self.boxSize, self.ylist[-2], fill=1, stroke=0)
97
self.canv.setFillGray(0.0)
99
#label each row and column
100
self.canv.setFont('Helvetica-Oblique',0.375 * self.boxSize)
102
for row in range(self.rows):
104
label = self.rowLabels[row]
105
else: # format start bytes as hex or decimal
106
label = self.formatByte(row * self.charsPerRow)
107
self.canv.drawCentredString(0.5 * self.boxSize,
108
(self.rows - row - 0.75) * self.boxSize,
111
for col in range(self.charsPerRow):
112
self.canv.drawCentredString((col + 1.5) * self.boxSize,
113
(self.rows + 0.25) * self.boxSize,
118
self.canv.setFont('Helvetica-BoldOblique',0.5 * self.boxSize)
119
self.canv.drawCentredString(0.5 * self.boxSize,
120
(self.rows + 0.25) * self.boxSize,
124
class SingleByteEncodingChart(CodeChartBase):
125
def __init__(self, faceName='Helvetica', encodingName='WinAnsiEncoding',
126
charsPerRow=16, boxSize=14, hex=1):
127
self.codePoints = 256
128
self.faceName = faceName
129
self.encodingName = encodingName
130
self.fontName = self.faceName + '-' + self.encodingName
131
self.charsPerRow = charsPerRow
132
self.boxSize = boxSize
134
self.rowLabels = None
135
pdfmetrics.registerFont(pdfmetrics.Font(self.fontName,
145
charList = [None] * 32 + map(chr, range(32, 256))
146
self.drawChars(charList)
147
self.canv.grid(self.xlist, self.ylist)
150
class KutenRowCodeChart(CodeChartBase):
151
"""Formats one 'row' of the 94x94 space used in many Asian encodings.aliases
153
These deliberately resemble the code charts in Ken Lunde's "Understanding
154
CJKV Information Processing", to enable manual checking. Due to the large
155
numbers of characters, we don't try to make one graphic with 10,000 characters,
156
but rather output a sequence of these."""
157
#would be cleaner if both shared one base class whose job
158
#was to draw the boxes, but never mind...
159
def __init__(self, row, faceName, encodingName):
163
self.charsPerRow = 20
165
self.rowLabels = ['00','20','40','60','80']
167
self.faceName = faceName
168
self.encodingName = encodingName
171
# the dependent files might not be available
172
font = cidfonts.CIDFont(self.faceName, self.encodingName)
173
pdfmetrics.registerFont(font)
175
# fall back to English and at least shwo we can draw the boxes
176
self.faceName = 'Helvetica'
177
self.encodingName = 'WinAnsiEncoding'
178
self.fontName = self.faceName + '-' + self.encodingName
181
def makeRow(self, row):
182
"""Works out the character values for this kuten row"""
184
if string.find(self.encodingName, 'EUC') > -1:
185
# it is an EUC family encoding.
186
for col in range(1, 95):
187
ch = chr(row + 160) + chr(col+160)
189
## elif string.find(self.encodingName, 'GB') > -1:
190
## # it is an EUC family encoding.
191
## for col in range(1, 95):
192
## ch = chr(row + 160) + chr(col+160)
194
cells.append([None] * 94)
198
self.drawLabels(topLeft= 'R%d' % self.row)
200
# work out which characters we need for the row
201
#assert string.find(self.encodingName, 'EUC') > -1, 'Only handles EUC encoding today, you gave me %s!' % self.encodingName
203
# pad out by 1 to match Ken Lunde's tables
204
charList = [None] + self.makeRow(self.row)
205
self.drawChars(charList)
206
self.canv.grid(self.xlist, self.ylist)
209
class Big5CodeChart(CodeChartBase):
210
"""Formats one 'row' of the 94x160 space used in Big 5
212
These deliberately resemble the code charts in Ken Lunde's "Understanding
213
CJKV Information Processing", to enable manual checking."""
214
def __init__(self, row, faceName, encodingName):
216
self.codePoints = 160
218
self.charsPerRow = 16
221
self.faceName = faceName
222
self.encodingName = encodingName
223
self.rowLabels = ['4','5','6','7','A','B','C','D','E','F']
225
# the dependent files might not be available
226
font = cidfonts.CIDFont(self.faceName, self.encodingName)
227
pdfmetrics.registerFont(font)
229
# fall back to English and at least shwo we can draw the boxes
230
self.faceName = 'Helvetica'
231
self.encodingName = 'WinAnsiEncoding'
232
self.fontName = self.faceName + '-' + self.encodingName
235
def makeRow(self, row):
236
"""Works out the character values for this Big5 row.
237
Rows start at 0xA1"""
239
if string.find(self.encodingName, 'B5') > -1:
240
# big 5, different row size
241
for y in [4,5,6,7,10,11,12,13,14,15]:
244
ch = chr(row) + chr(col)
248
cells.append([None] * 160)
252
self.drawLabels(topLeft='%02X' % self.row)
254
charList = self.makeRow(self.row)
255
self.drawChars(charList)
256
self.canv.grid(self.xlist, self.ylist)
259
def hBoxText(msg, canvas, x, y, faceName, encName):
260
"""Helper for stringwidth tests on Asian fonts.
262
Registers font if needed. Then draws the string,
263
and a box around it derived from the stringWidth function"""
265
fontName = faceName + '-' + encName
267
font = pdfmetrics.getFont(fontName)
269
font = cidfonts.CIDFont(faceName, encName)
270
pdfmetrics.registerFont(font)
272
canvas.setFillGray(0.8)
273
canvas.rect(x,y,pdfmetrics.stringWidth(msg, fontName, 16),16,stroke=0,fill=1)
274
canvas.setFillGray(0)
275
canvas.setFont(fontName, 16,16)
276
canvas.drawString(x,y,msg)
277
canvas.restoreState()
280
class CodeWidget(Widget):
281
"""Block showing all the characters"""
289
dx = self.width / 16.0
290
dy = self.height / 16.0
292
g.add(Rect(self.x, self.y, self.width, self.height,
293
fillColor=None, strokeColor=colors.black))
296
charValue = y * 16 + x
298
s = String(self.x + x * dx,
299
self.y + (self.height - y*dy), chr(charValue))
309
c = Canvas('codecharts.pdf')
310
c.setFont('Helvetica-Bold', 24)
311
c.drawString(72, 750, 'Testing code page charts')
312
cc1 = SingleByteEncodingChart()
313
cc1.drawOn(c, 72, 500)
315
cc2 = SingleByteEncodingChart(charsPerRow=32)
316
cc2.drawOn(c, 72, 300)
318
cc3 = SingleByteEncodingChart(charsPerRow=25, hex=0)
319
cc3.drawOn(c, 72, 100)
323
## c.setFont('Helvetica-Bold', 24)
324
## c.drawString(72, 750, 'Multi-byte Kuten code chart examples')
325
## KutenRowCodeChart(1, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 600)
326
## KutenRowCodeChart(16, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 450)
327
## KutenRowCodeChart(84, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 300)
330
## c.setFont('Helvetica-Bold', 24)
331
## c.drawString(72, 750, 'Big5 Code Chart Examples')
332
## #Big5CodeChart(0xA1, 'MSungStd-Light-Acro','ETenms-B5-H').drawOn(c, 72, 500)
335
print 'saved codecharts.pdf'
337
if __name__=='__main__':