1#aigen.py 2""" 3This is a library to generate AI files containing text and graphics. It is 4part of the Adobe Illustrator format backend for PIDDLE foundation for a 5complete Reporting solution in Python. 6 7(C) Copyright Bill Bedford 1999 8parts (C) Copyright Andy Robinson 1998-1999 9""" 10 11import os 12import sys 13import string 14import time 15import tempfile 16from types import * 17 18 19############################################################## 20# 21# Constants and declarations 22# 23############################################################## 24 25 26 27StandardEnglishFonts = [ 28 'Courier', 'Courier-Bold', 'Courier-Oblique', 'Courier-BoldOblique', 29 'Helvetica', 'Helvetica-Bold', 'Helvetica-Oblique', 30 'Helvetica-BoldOblique', 31 'Times-Roman', 'Times-Bold', 'Times-Italic', 'Times-BoldItalic', 32 'Symbol','ZapfDingbats'] 33 34AIError = 'AIError' 35AFMDIR = '.' 36 37############################################################## 38# 39# AI Metrics 40# This is a preamble to give us a stringWidth function. 41# loads and caches AFM files, but won't need to as the 42# standard fonts are there already 43############################################################## 44 45widths = {'courier': [ 460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 470,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 48600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 49600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 50600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 51600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 52600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 53600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,0, 540,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 560,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 570,600,600,600,600,0,600,600,600,600,600,600,600,600,0,600, 580,600,600,600,600,600,600,600,600,0,600,600,0,600,600,600, 59600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 600,600,0,600,0,0,0,0,600,600,600,600,0,0,0,0, 610,600,0,0,0,600,0,0,600,600,600,600,0,0,600], 62'courier-bold': [ 630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 65600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 66600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 67600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 68600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 69600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 70600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,0, 710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 730,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 740,600,600,600,600,0,600,600,600,600,600,600,600,600,0,600, 750,600,600,600,600,600,600,600,600,0,600,600,0,600,600,600, 76600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 770,600,0,600,0,0,0,0,600,600,600,600,0,0,0,0, 780,600,0,0,0,600,0,0,600,600,600,600,0,0,600], 79'courier-boldoblique': [ 800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 82600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 83600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 84600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 85600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 86600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 87600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,0, 880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 900,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 910,600,600,600,600,0,600,600,600,600,600,600,600,600,0,600, 920,600,600,600,600,600,600,600,600,0,600,600,0,600,600,600, 93600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 940,600,0,600,0,0,0,0,600,600,600,600,0,0,0,0, 950,600,0,0,0,600,0,0,600,600,600,600,0,0,600], 96'courier-oblique': [ 970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 99600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 100600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 101600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 102600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 103600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 104600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,0, 1050,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1060,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1070,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600, 1080,600,600,600,600,0,600,600,600,600,600,600,600,600,0,600, 1090,600,600,600,600,600,600,600,600,0,600,600,0,600,600,600, 110600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1110,600,0,600,0,0,0,0,600,600,600,600,0,0,0,0, 1120,600,0,0,0,600,0,0,600,600,600,600,0,0,600], 113'helvetica': [ 1140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 116278,278,355,556,556,889,667,222,333,333,389,584,278,333,278,278, 117556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556, 1181015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778, 119667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556, 120222,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556, 121556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,0, 1220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1240,333,556,556,167,556,556,556,556,191,333,556,333,333,500,500, 1250,556,556,556,278,0,537,350,222,333,333,556,1000,1000,0,611, 1260,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 1271000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1280,1000,0,370,0,0,0,0,556,778,1000,365,0,0,0,0, 1290,889,0,0,0,278,0,0,222,611,944,611,0,0,834], 130'helvetica-bold': [ 1310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 133278,333,474,556,556,889,722,278,333,333,389,584,278,333,278,278, 134556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611, 135975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778, 136667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556, 137278,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611, 138611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,0, 1390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1410,333,556,556,167,556,556,556,556,238,500,556,333,333,611,611, 1420,556,556,556,278,0,556,350,278,500,500,556,1000,1000,0,611, 1430,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 1441000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1450,1000,0,370,0,0,0,0,611,778,1000,365,0,0,0,0, 1460,889,0,0,0,278,0,0,278,611,944,611,0,0,834], 147'helvetica-boldoblique': [ 1480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 150278,333,474,556,556,889,722,278,333,333,389,584,278,333,278,278, 151556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611, 152975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778, 153667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556, 154278,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611, 155611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,0, 1560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1570,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1580,333,556,556,167,556,556,556,556,238,500,556,333,333,611,611, 1590,556,556,556,278,0,556,350,278,500,500,556,1000,1000,0,611, 1600,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 1611000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1620,1000,0,370,0,0,0,0,611,778,1000,365,0,0,0,0, 1630,889,0,0,0,278,0,0,278,611,944,611,0,0,834], 164'helvetica-oblique': [ 1650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 167278,278,355,556,556,889,667,222,333,333,389,584,278,333,278,278, 168556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556, 1691015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778, 170667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556, 171222,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556, 172556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,0, 1730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1750,333,556,556,167,556,556,556,556,191,333,556,333,333,500,500, 1760,556,556,556,278,0,537,350,222,333,333,556,1000,1000,0,611, 1770,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 1781000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1790,1000,0,370,0,0,0,0,556,778,1000,365,0,0,0,0, 1800,889,0,0,0,278,0,0,222,611,944,611,0,0,834], 181'symbol': [ 1820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 184250,333,713,500,549,833,778,439,333,333,500,549,250,549,250,278, 185500,500,500,500,500,500,500,500,500,500,278,278,549,549,549,444, 186549,722,667,722,612,611,763,603,722,333,631,722,686,889,722,722, 187768,741,556,592,611,690,439,768,645,795,611,333,863,333,658,500, 188500,631,549,549,494,439,521,411,603,329,603,549,549,576,521,549, 189549,521,549,603,439,576,713,686,493,686,494,480,200,480,549,0, 1900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1920,620,247,549,167,713,500,753,753,753,753,1042,987,603,987,603, 193400,549,411,549,549,713,494,460,549,549,549,549,1000,603,1000,658, 194823,686,795,987,768,768,823,768,768,713,713,713,713,713,713,713, 195768,713,790,790,890,823,549,250,713,603,603,1042,987,603,987,603, 196494,329,790,790,786,713,384,384,384,384,384,384,494,494,494,494, 1970,329,274,686,686,686,384,384,384,384,384,384,494,494,790], 198'times-bold': [ 1990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 201250,333,555,500,500,1000,833,333,333,333,500,570,250,333,250,278, 202500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500, 203930,722,667,722,722,667,611,778,778,389,500,778,667,944,722,778, 204611,778,722,556,667,722,722,1000,722,722,667,333,278,333,581,500, 205333,500,556,444,556,444,333,500,556,278,333,556,278,833,556,500, 206556,556,444,389,333,556,500,722,500,500,444,394,220,394,520,0, 2070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2090,333,500,500,167,500,500,500,500,278,500,500,333,333,556,556, 2100,500,500,500,250,0,540,350,333,500,500,500,1000,1000,0,500, 2110,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 2121000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2130,1000,0,300,0,0,0,0,667,778,1000,330,0,0,0,0, 2140,722,0,0,0,278,0,0,278,500,722,556,0,0,750], 215'times-bolditalic': [ 2160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 218250,389,555,500,500,833,778,333,333,333,500,570,250,333,250,278, 219500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500, 220832,667,667,667,722,667,667,722,778,389,500,667,611,889,722,722, 221611,722,667,556,611,722,667,889,667,611,611,333,278,333,570,500, 222333,500,500,444,500,444,333,500,556,278,278,500,278,778,556,500, 223500,500,389,389,278,556,444,667,500,444,389,348,220,348,570,0, 2240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2260,389,500,500,167,500,500,500,500,278,500,500,333,333,556,556, 2270,500,500,500,250,0,500,350,333,500,500,500,1000,1000,0,500, 2280,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 2291000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2300,944,0,266,0,0,0,0,611,722,944,300,0,0,0,0, 2310,722,0,0,0,278,0,0,278,500,722,500,0,0,750], 232'times-italic': [ 2330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 235250,333,420,500,500,833,778,333,333,333,500,675,250,333,250,278, 236500,500,500,500,500,500,500,500,500,500,333,333,675,675,675,500, 237920,611,611,667,722,611,611,722,722,333,444,667,556,833,667,722, 238611,722,611,500,556,722,611,833,611,556,556,389,278,389,422,500, 239333,500,500,444,500,444,278,500,500,278,278,444,278,722,500,500, 240500,500,389,389,278,500,444,667,444,444,389,400,275,400,541,0, 2410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2420,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2430,389,500,500,167,500,500,500,500,214,556,500,333,333,500,500, 2440,500,500,500,250,0,523,350,333,556,556,500,889,1000,0,500, 2450,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 246889,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2470,889,0,276,0,0,0,0,556,722,944,310,0,0,0,0, 2480,667,0,0,0,278,0,0,278,500,667,500,0,0,750], 249'times-roman': [ 2500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2510,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 252250,333,408,500,500,833,778,333,333,333,500,564,250,333,250,278, 253500,500,500,500,500,500,500,500,500,500,278,278,564,564,564,444, 254921,722,667,667,722,611,556,722,722,333,389,722,611,889,722,722, 255556,722,667,556,611,722,722,944,722,722,611,333,278,333,469,500, 256333,444,500,444,500,444,333,500,500,278,278,500,278,778,500,500, 257500,500,333,389,278,500,500,722,500,500,444,480,200,480,541,0, 2580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2590,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2600,333,500,500,167,500,500,500,500,180,444,500,333,333,556,556, 2610,500,500,500,250,0,453,350,333,444,444,500,1000,1000,0,444, 2620,333,333,333,333,333,333,333,333,0,333,333,0,333,333,333, 2631000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2640,889,0,276,0,0,0,0,611,722,889,310,0,0,0,0, 2650,667,0,0,0,278,0,0,278,500,722,500,0,0,750], 266'zapfdingbats': [ 2670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 269278,974,961,974,980,719,789,790,791,690,960,939,549,855,911,933, 270911,945,974,755,846,762,761,571,677,763,760,759,754,494,552,537, 271577,692,786,788,788,790,793,794,816,823,789,841,823,833,816,831, 272923,744,723,749,790,792,695,776,768,792,759,707,708,682,701,826, 273815,789,789,707,687,696,689,786,787,713,791,785,791,873,761,762, 274762,759,759,892,892,788,784,438,138,277,415,392,392,668,668,0, 2750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2770,732,544,544,910,667,760,760,776,595,694,626,788,788,788,788, 278788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788, 279788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788, 280788,788,788,788,894,838,1016,458,748,924,748,918,927,928,928,834, 281873,828,924,924,917,930,931,463,883,836,836,867,867,696,696,874, 2820,874,760,946,771,865,771,888,967,888,831,873,927,970,234] 283} 284 285ascent_descent = {'Courier': (629, -157), 286 'Courier-Bold': (626, -142), 287 'Courier-BoldOblique': (626, -142), 288 'Courier-Oblique': (629, -157), 289 'Helvetica': (718, -207), 290 'Helvetica-Bold': (718, -207), 291 'Helvetica-BoldOblique': (718, -207), 292 'Helvetica-Oblique': (718, -207), 293 'Symbol': (0, 0), 294 'Times-Bold': (676, -205), 295 'Times-BoldItalic': (699, -205), 296 'Times-Italic': (683, -205), 297 'Times-Roman': (683, -217), 298 'ZapfDingbats': (0, 0)} 299 300 301def parseAFMfile(filename): 302 """Returns an array holding the widths of all characters in the font. 303 Ultra-crude parser""" 304 alllines = open(filename, 'r').readlines() 305 # get stuff between StartCharMetrics and EndCharMetrics 306 metriclines = [] 307 between = 0 308 for line in alllines: 309 if string.find(string.lower(line), 'endcharmetrics') > -1: 310 between = 0 311 break 312 if between: 313 metriclines.append(line) 314 if string.find(string.lower(line), 'startcharmetrics') > -1: 315 between = 1 316 317 # break up - very shaky assumption about array size 318 widths = [0] * 255 319 320 for line in metriclines: 321 chunks = string.split(line, ';') 322 323 (c, cid) = string.split(chunks[0]) 324 (wx, width) = string.split(chunks[1]) 325 #(n, name) = string.split(chunks[2]) 326 #(b, x1, y1, x2, y2) = string.split(chunks[3]) 327 widths[string.atoi(cid)] = string.atoi(width) 328 329 # by default, any empties should get the width of a space 330 for i in range(len(widths)): 331 if widths[i] == 0: 332 widths[i] == widths[32] 333 334 return widths 335 336 337class FontCache: 338 """Loads and caches font width information on demand. Font names 339 converted to lower case for indexing. Public interface is stringwidth""" 340 def __init__(self): 341 global widths 342 self.__widtharrays = widths 343 344 345 def loadfont(self, fontname): 346 filename = AFMDIR + os.sep + fontname + '.afm' 347 print 'cache loading',filename 348 assert os.path.exists(filename) 349 widths = parseAFMfile(filename) 350 self.__widtharrays[fontname] = widths 351 def getfont(self, fontname): 352 try: 353 return self.__widtharrays[fontname] 354 except: 355 try: 356 self.loadfont(fontname) 357 return self.__widtharrays[fontname] 358 except: 359 # font not found, use Courier 360 print 'Font',fontname,'not found - using Courier for widths' 361 return self.getfont('courier') 362 363 364 def stringwidth(self, text, font): 365 widths = self.getfont(string.lower(font)) 366 w = 0 367 for char in text: 368 w = w + widths[ord(char)] 369 return w 370 def status(self): 371 #returns loaded fonts 372 return self.__widtharrays.keys() 373 374TheFontCache = FontCache() 375 376stringwidth = TheFontCache.stringwidth 377 378 379############################################################## 380# 381# AI Document 382# 383############################################################## 384 385 386class AIDocument: 387 def __init__(self): 388 self.objects = [] 389 self.info = AIHeader() #hang onto it! 390 self.add(self.info) 391 self.transforms = AIStream() 392 393 self.pages = [] 394 self.pagepositions = [] 395 self.infopos = 19 396 397 # position 1 398# cat = AICatalog() 399# cat.RefPages = 3 400# cat.RefOutlines = 2 401# self.add(cat) 402 403 # position 2 - outlines 404# outl = AIOutline() 405# self.add(outl) 406 407 # position 3 - pages collection 408# self.PageCol = AIPageCollection() 409# self.add(self.PageCol) 410 411 # positions 4-17 - fonts 412# fonts = MakeType1Fonts() 413# for font in fonts: 414# self.add(font) 415# 416# self.fontdict = MakeFontDictionary(4, 15) 417 418 # position 18 - Info 419 420 421 # testing here - position 19 - an image 422 self.add(AIProlog()) 423 self.add(AISetUp()) 424# self.add(AIStream()) 425# self.add(AIImage()) 426 self.add(self.transforms) 427 428 def add(self, obj): 429 self.objects.append(obj) 430 obj.doc = self 431 432 def setTitle(self, title): 433 "embeds in AI file" 434 self.info.title = title 435 436 def setAuthor(self, author): 437 "embedded in AI file" 438 self.info.author = author 439 440 def setBoundingBox(self, boundingbox): 441 "embeds in AI file" 442 self.transforms.originx = 0 443 self.transforms.originy = 0 444# self.info.boundingBox = boundingbox 445 lx,ly, ux,uy, tx = boundingbox 446 print 'setBoundingBox', lx,ly, ux,uy, tx 447 print 'setBoundingBox', ux-lx,uy-ly 448 self.info.pagesize = (ux-lx), (uy-ly) 449 ##XXX If the ArtSize is smaller than Letter Freehand always draws the 450 ##XXX origin as if the Art board was Letter sized, however the arboard 451 ##XXX is drawn at the same center as a letter sized artboard. 452 ##XXX hence this translation 453 if ux-lx < 612: 454 self.transforms.originx = w = (612 - (ux-lx))/2 +tx 455 lx, ux = lx + w, ux + w 456 if uy-ly < 792: 457 self.transforms.originy = w = (792 - (uy-ly))/2 +tx 458 ly, uy = ly + w, uy + w 459# print self.transforms 460# print self.transforms.originx 461# print self.transforms.originy 462 print 'setBoundingBox', lx,ly, ux,uy 463 self.info.boundingBox = lx, ly, ux, uy 464 self.transforms.height = uy 465 466 def setPage(self, page): 467# print 'setPage', page 468 self.transforms.data = page 469 470 471 def SaveToFile(self, filename): 472# print 'SaveToFile', self.transforms.originx, self.transforms.originy 473 f = open(filename, 'w') 474 old_output = sys.stdout 475 sys.stdout = f 476 self.printAI() 477 sys.stdout = old_output 478 f.close() 479 480 def printXref(self): 481 self.startxref = sys.stdout.tell() 482 print 'xref' 483 print 0,len(self.objects) + 1 484 print '0000000000 65535 f' 485 for pos in self.xref: 486 print '%0.10d 00000 n' % pos 487 488 def printTrailer(self): 489 print '''%%PageTrailer 490gsave annotatepage grestore showpage 491%%Trailer''' 492# print '<< /Size %d /Root %d 0 R /Info %d 0 R>>' % (len(self.objects) + 1, 1, self.infopos) 493# print 'startxref' 494# print self.startxref 495 496 def printAI(self): 497 "prints it to standard output. Logs positions for doing trailer" 498# print "%AI-1.0" 499# print "%����" 500 i = 1 501 self.xref = [] 502# print self.objects 503 for obj in self.objects: 504# print 'printAI', obj 505# pos = sys.stdout.tell() 506# self.xref.append(pos) 507# print i, '0 obj' 508 obj.printAI() 509# print 'endobj' 510# i = i + 1 511# self.printXref() 512 self.printTrailer() 513 print "%%EOF", 514 515 516 def addPage(self, page): 517 """adds page and stream at end. Maintains pages list""" 518 #page.buildstream() 519 pos = len(self.objects) # work out where added 520 521# page.ParentPos = 3 #pages collection 522# page.info = {'parentpos':3, 523# 'fontdict':self.fontdict, 524# 'contentspos':pos + 2} 525 526# self.PageCol.PageList.append(pos+1) 527# print 'addPage', self.transforms.setStream((10, 20, 'm')) 528# print 'addPage', self.transforms.setStream(page) 529# self.page = 530 self.transforms.data = page 531# print 'addPage', self.page 532# self.objects.append(page) 533# self.objects.append(self.page) 534 535 536 537############################################################## 538# 539# Utilities 540# 541############################################################## 542 543class OutputGrabber: 544 """At times we need to put something in the place of standard 545 output. This grabs stdout, keeps the data, and releases stdout 546 when done. 547 548 NOT working well enough!""" 549 def __init__(self): 550 self.oldoutput = sys.stdout 551 sys.stdout = self 552 self.closed = 0 553 self.data = [] 554 def write(self, x): 555 if not self.closed: 556 self.data.append(x) 557 558 def getData(self): 559 return string.join(self.data) 560 561 def close(self): 562 sys.stdout = self.oldoutput 563 self.closed = 1 564 565 def __del__(self): 566 if not self.closed: 567 self.close() 568 569 570def testOutputGrabber(): 571 gr = OutputGrabber() 572 for i in range(10): 573 print 'line',i 574 data = gr.getData() 575 gr.close() 576 print 'Data...',data 577 578 579############################################################## 580# 581# AI Object Hierarchy 582# 583############################################################## 584 585 586 587class AIObject: 588 "Base class for all AI objects" 589 def printAI(self): 590 print '% base AI object' 591 592 593class AILiteral(AIObject): 594 " a ready-made one you wish to quote" 595 def __init__(self, text): 596 self.text = text 597 def printAI(self): 598 print self.text 599 600 601 602class AICatalog(AIObject): 603 "requires RefPages and RefOutlines set" 604 def __init__(self): 605 self.template = '''<< 606/Type /Catalog 607/Pages %d 0 R 608/Outlines %d 0 R 609>>''' 610 def printAI(self): 611 print self.template % (self.RefPages, self.RefOutlines) 612 613class AIHeader(AIObject): 614 # no features implemented yet 615 def __init__(self): 616 self.title = "untitled" 617 self.author = "anonymous" 618 self.boundingBox = (0, 0, 565, 842) 619 self.pagesize = (565, 842) 620 self.rulerUnits = 2 621 now = time.localtime(time.time()) 622 self.datestr = time.strftime("%x %I:%M %p", now) 623 624 def printAI(self): 625 print "%!PS-Adobe-3.0" 626 print "%%Creator: PIDDLE Adobe Illustrator backend" 627 print "%%Title: " +'(%s)' % self.title 628 print "%%For: " +'(%s)' % self.author 629 print "%%CreationDate: " +'(%s)' % self.datestr 630 print "%%DocumentProcessColors: Black""" 631 print '%%BoundingBox: ' + '%s %s %s %s' % self.boundingBox 632 #%%DocumentProcessColors: Cyan Magenta Yellow 633 #%%DocumentCustomColors: (PANTONE 156 CV) 634 #%%RGBCustomColor: red green blue (customcolorname) 635 #%%DocumentFonts: CooperBlack 636 #%%+ Minion-Regular 637 #%%DocumentFiles: WrathOfRalph 638 print "%AI5_FileFormat 3" 639 print "%AI3_ColorUsage: Color" 640 print '%AI5_ArtSize: ' + '%s %s' % self.pagesize 641 print '%AI5_Templatebox: ' + '%s %s' % self.pagesize 642 #%AI7_ImageSettings: flag 643 print '%AI5_TargetResolution: 300' 644 print '%%EndComments' 645 646 647class AIProlog(AIObject): 648 "null outline, does nothing yet" 649 def __init__(self): 650 self.FontList = [] 651 def printAI(self): 652 print '%%BeginProlog' 653 print '%%EndProlog' 654 655class AISetUp(AIObject): 656 "null outline, does nothing yet" 657 def __init__(self): 658 self.FontList = [] 659 def printAI(self): 660 print '%%BeginSetup' 661 if self.FontList: 662 pass 663 print '%%EndSetup' 664 665class AIPageCollection(AIObject): 666 "presumes PageList attribute set (list of integers)" 667 def __init__(self): 668 self.PageList = [] 669 def printAI(self): 670 result = '<<\n/Type /Pages\n/Count %d\n/Kids [' % len(self.PageList) 671 for page in self.PageList: 672 result = result + str(page) + ' 0 R ' 673 result = result + ']\n>>' 674 print result 675 676#class AIBody(AIObject): 677# """The Bastard. Needs list of Resources etc. Use a standard one for now. 678# It manages a AIStream object which must be added to the document's list 679# os objects as well.""" 680# def __init__(self): 681# self.drawables = [] 682# self.stream = AIStream() 683# self.hasImages = 0 684# self.template = """<< 685#/Type /Page 686#/Parent %(parentpos)d 0 R 687#/Resources 688# << 689# /Font %(fontdict)s 690# /ProcSet %(procsettext)s 691# >> 692#/MediaBox [0 0 595 842] 693#/Contents %(contentspos)d 0 R 694#>>""" 695# def printAI(self): 696# # check for image support 697## if self.hasImages: 698## self.info['procsettext'] = '[/AI /Text /ImageC]' 699## else: 700## self.info['procsettext'] = '[/AI /Text]' 701## 702## print self.template % self.info 703# print "AIBody.printAI(self)" 704# 705# def clear(self): 706# self.drawables = [] 707# 708# def setStream(self, data): 709# self.stream.setStream(data) 710# 711# 712# #def add(self, drawable): 713# # self.drawables.append(drawable) 714# # 715# #def buildstream(self): 716# # textmode = 0 717# # 718# # oldout = sys.stdout 719# # fn = tempfile.mktemp() 720# # #f = open(fn, 'wb') #AR 19980202 721# # f = open(fn, 'w') 722# # sys.stdout = f 723# # text = 0 724# # for obj in self.drawables: 725# # if obj.isText(): 726# # if text == 0: 727# # print 'BT' 728# # text = 1 729# # else: 730# # if text == 1: 731# # print 'ET' 732# # text = 0 733# # 734# # obj.printAI() 735# # if self.drawables[-1].isText(): 736# # print 'ET' 737# # sys.stdout = oldout 738# # f.close() 739# # 740# # self.stream = AIStream() 741# # #self.stream.data = open(fn,'r').read() 742# # self.stream.data = open(fn,'rb').read() #AR 19980202 743# 744# 745# 746# 747TestStream = ['q', (72, 720, 'l'), 'S', 'Q', (80, 672, 'm'), (24, 'TL'), 748(('Test Page with no stream'), 'Tj', 'T*')] 749 750 751class AIStream(AIObject): 752 "Used for the contents of a page" 753 def __init__(self): 754 self.data = [] 755 self.originx = 0 756 self.originy = 0 757 self.height = 0 758 759# def setStream(self, data): 760# self.data = data 761# print 'setStream', self.originy, self.originy 762# print self.data 763 764 def printAI(self): 765 # test code is useful 766 if self.data == None: 767 self.data = TestStream 768 # the AI length key should contain the length including 769 # any extra LF pairs added by Print on DOS. 770 771# lines = len(string.split(self.data,'\n')) 772# length = len(self.data) + lines # one extra LF each 773 #length = len(self.data) #AR 19980202 774# print 'printAI', self.originx, self.originy 775# print 'printAI', self.transformAI(self.originx, self.originy, self.height) 776 777 778# print '<< /Length %d >>' % length 779 print '''%AI5_BeginLayer 7801 1 1 1 0 0 0 79 128 255 Lb 781(Foreground) Ln''' 782 print self.transformAI(self.originx, self.originy, self.height) 783 784# print 'XXXX', self.data 785 print '''LB 786%AI5_EndLayer--''' 787 788 def transformAI(self, ox, oy, ty): 789# print 'transformAI', ox, oy 790# print 'transformAI', self.data, type(self.data) 791 page = [] 792 for line in self.data: 793# print line 794 if type(line) == TupleType and len(line) == 3: 795# print 'x', line 796 line = line[0]+ ox, line[1]+oy, line[2] 797 line = line[0], oy + ty -line[1], line[2] 798 line = '%f %f %s' % line 799 elif type(line) == TupleType and len(line) == 7: 800 line = line[0]+ox, line[1]+oy, line[2]+ox, line[3]+oy, line[4]+ox, line[5]+oy, line[6] 801 line = line[0], oy+ty-line[1], line[2], oy+ty-line[3], line[4], oy+ty-line[5], line[6] 802 line = '%f %f %f %f %f %f %s' % line 803# print line 804 page.append(line) 805 return string.join(page, '\n') 806 807class AIImage(AIObject): 808 def printAI(self): 809 print """<< 810/Type /XObject 811/Subtype /Image 812/Name /Im0 813/Width 24 814/Height 23 815/BitsPerComponent 1 816/ColorSpace /DeviceGray 817/Filter /ASCIIHexDecode 818/Length 174 819>> 820stream 821003B00 002700 002480 0E4940 114920 14B220 3CB650 82275FE88 17FF8C 175F14 1C07E2 3803C4 703182 F8EDFC 823B2BBC2 BB6F84 31BFC2 18EA3C 0E3E00 07FC00 03F800 8241E1800 1FF800> 825endstream 826endobj""" 827 828class AIType1Font(AIObject): 829 def __init__(self, key, font): 830 self.fontname = font 831 self.keyname = key 832 self.template = """<< 833/Type /Font 834/Subtype /Type1 835/Name /%s 836/BaseFont /%s 837/Encoding /WinAnsiEncoding 838>>""" 839 def printAI(self): 840 print self.template % (self.keyname, self.fontname) 841 842class AIProcSet(AIObject): 843 def printAI(self): 844 print "[/AI /Text]" 845 846 847 848 849 850 851 852############################################################## 853# 854# some helpers 855# 856############################################################## 857 858def MakeType1Fonts(): 859 "returns a list of all the standard font objects" 860 fonts = [] 861 pos = 1 862 for fontname in StandardEnglishFonts: 863 font = AIType1Font('F'+str(pos), fontname) 864 fonts.append(font) 865 pos = pos + 1 866 return fonts 867 868def MakeFontDictionary(startpos, count): 869 "returns a font dictionary assuming they are all in the file from startpos" 870 dict = " << \n" 871 pos = startpos 872 for i in range(count-1): 873 dict = dict + '\t\t/F%d %d 0 R \n' % (i + 1, startpos + i) 874 dict = dict + " >>\n" 875 return dict 876 877 878#if __name__ == '__main__': 879# print 'For test scripts, run test1.py to test7.py'