git: f744cf12e017 - main - graphics/piddle: Fix build with setuptools 58.0.0+

From: Po-Chuan Hsieh <sunpoet_at_FreeBSD.org>
Date: Fri, 25 Mar 2022 13:50:30 UTC
The branch main has been updated by sunpoet:

URL: https://cgit.FreeBSD.org/ports/commit/?id=f744cf12e017c9230e7d24f05aa7b60c70cad305

commit f744cf12e017c9230e7d24f05aa7b60c70cad305
Author:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
AuthorDate: 2022-03-25 13:32:36 +0000
Commit:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
CommitDate: 2022-03-25 13:38:16 +0000

    graphics/piddle: Fix build with setuptools 58.0.0+
    
    With hat:       python
---
 graphics/piddle/files/patch-2to3 | 2238 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 2238 insertions(+)

diff --git a/graphics/piddle/files/patch-2to3 b/graphics/piddle/files/patch-2to3
new file mode 100644
index 000000000000..2393103c2106
--- /dev/null
+++ b/graphics/piddle/files/patch-2to3
@@ -0,0 +1,2238 @@
+--- src/piddle/PixMapWrapper.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/PixMapWrapper.py
+@@ -93,7 +93,7 @@ class PixMapWrapper:
+ 
+ 	def __setattr__(self, attr, val):
+ 		if attr == 'baseAddr':
+-			raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead"
++			raise('UseErr', "don't assign to .baseAddr -- assign to .data instead")
+ 		elif attr == 'data':
+ 			self.__dict__['data'] = val
+ 			self._stuff('baseAddr', id(self.data) + MacOS.string_id_to_buffer)
+@@ -109,7 +109,7 @@ class PixMapWrapper:
+ 		elif attr == 'hRes' or attr == 'vRes':
+ 			# 16.16 fixed format, so just shift 16 bits
+ 			self._stuff(attr, int(val) << 16)
+-		elif attr in _pmElemFormat.keys():
++		elif attr in list(_pmElemFormat.keys()):
+ 			# any other pm attribute -- just stuff
+ 			self._stuff(attr, val)
+ 		else:
+@@ -129,7 +129,7 @@ class PixMapWrapper:
+ 		elif attr == 'hRes' or attr == 'vRes':
+ 			# 16.16 fixed format, so just shift 16 bits
+ 			return self._unstuff(attr) >> 16
+-		elif attr in _pmElemFormat.keys():
++		elif attr in list(_pmElemFormat.keys()):
+ 			# any other pm attribute -- just unstuff
+ 			return self._unstuff(attr)
+ 		else:
+@@ -151,7 +151,7 @@ class PixMapWrapper:
+ 		if y2 == None:
+ 			dest[3] = y1 + src[3]-src[1]
+ 		if not port: port = Qd.GetPort()
+-		print "blit port:", port
++		print("blit port:", port)
+ 		Qd.CopyBits(self.PixMap(), port.portBits, src, tuple(dest),
+ 				QuickDraw.srcCopy, None)
+ 
+@@ -186,7 +186,7 @@ class PixMapWrapper:
+ 		# so convert if necessary
+ 		if format != imgformat.macrgb and format != imgformat.macrgb16:
+ 			# (LATER!)
+-			raise "NotImplementedError", "conversion to macrgb or macrgb16"
++			raise("NotImplementedError", "conversion to macrgb or macrgb16")
+ 		self.data = s
+ 		self.bounds = (0,0,width,height)
+ 		self.cmpCount = 3
+@@ -207,7 +207,7 @@ class PixMapWrapper:
+ 			return self.data
+ 		# otherwise, convert to the requested format
+ 		# (LATER!)
+-			raise "NotImplementedError", "data format conversion"
++			raise("NotImplementedError", "data format conversion")
+ 
+ 	def fromImage(self,im):
+ 		"""Initialize this PixMap from a PIL Image object."""
+--- src/piddle/aigen.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/aigen.py
+@@ -344,7 +344,7 @@ class FontCache:
+ 		
+ 	def loadfont(self, fontname):
+ 		filename = AFMDIR + os.sep + fontname + '.afm'
+-		print 'cache loading',filename
++		print('cache loading',filename)
+ 		assert os.path.exists(filename)
+ 		widths = parseAFMfile(filename)
+ 		self.__widtharrays[fontname] = widths
+@@ -357,7 +357,7 @@ class FontCache:
+ 				return self.__widtharrays[fontname]
+ 			except:
+ 				# font not found, use Courier
+-				print 'Font',fontname,'not found - using Courier for widths'
++				print('Font',fontname,'not found - using Courier for widths')
+ 				return self.getfont('courier')
+ 	
+ 
+@@ -369,7 +369,7 @@ class FontCache:
+ 		return w
+ 	def status(self):
+ 		#returns loaded fonts
+-		return self.__widtharrays.keys()
++		return list(self.__widtharrays.keys())
+ 		
+ TheFontCache = FontCache()
+ 
+@@ -443,8 +443,8 @@ class AIDocument:
+ 		self.transforms.originy = 0
+ #		self.info.boundingBox = boundingbox
+ 		lx,ly, ux,uy, tx = boundingbox
+-		print 'setBoundingBox', lx,ly, ux,uy, tx
+-		print 'setBoundingBox', ux-lx,uy-ly
++		print('setBoundingBox', lx,ly, ux,uy, tx)
++		print('setBoundingBox', ux-lx,uy-ly)
+ 		self.info.pagesize = (ux-lx), (uy-ly)
+ 		##XXX If the ArtSize is smaller than Letter Freehand always draws the 
+ 		##XXX origin as if the Art board was Letter sized, however the arboard 
+@@ -459,7 +459,7 @@ class AIDocument:
+ #		print self.transforms
+ #		print self.transforms.originx
+ #		print self.transforms.originy
+-		print 'setBoundingBox', lx,ly, ux,uy
++		print('setBoundingBox', lx,ly, ux,uy)
+ 		self.info.boundingBox = lx, ly, ux, uy
+ 		self.transforms.height = uy
+ 		
+@@ -479,16 +479,16 @@ class AIDocument:
+ 	
+ 	def printXref(self):
+ 		self.startxref = sys.stdout.tell()
+-		print 'xref'
+-		print 0,len(self.objects) + 1
+-		print '0000000000 65535 f'
++		print('xref')
++		print(0,len(self.objects) + 1)
++		print('0000000000 65535 f')
+ 		for pos in self.xref:
+-			print '%0.10d 00000 n' % pos
++			print('%0.10d 00000 n' % pos)
+ 	
+ 	def printTrailer(self):
+-		print '''%%PageTrailer
++		print('''%%PageTrailer
+ gsave annotatepage grestore showpage
+-%%Trailer'''
++%%Trailer''')
+ #		print '<< /Size %d /Root %d 0 R /Info %d 0 R>>' % (len(self.objects) + 1, 1, self.infopos)
+ #		print 'startxref'
+ #		print self.startxref
+@@ -496,7 +496,6 @@ gsave annotatepage grestore showpage
+ 	def printAI(self):
+ 		"prints it to standard output.  Logs positions for doing trailer"
+ #		print "%AI-1.0"
+-#		print "%’“¦²"
+ 		i = 1
+ 		self.xref = []
+ #		print self.objects
+@@ -510,7 +509,7 @@ gsave annotatepage grestore showpage
+ #			i = i + 1
+ #		self.printXref()
+ 		self.printTrailer()
+-		print "%%EOF",
++		print("%%EOF", end=' ')
+ 
+ 
+ 	def addPage(self, page):
+@@ -570,10 +569,10 @@ class OutputGrabber:
+ def testOutputGrabber():
+ 	gr = OutputGrabber()
+ 	for i in range(10):
+-		print 'line',i
++		print('line',i)
+ 	data = gr.getData()
+ 	gr.close()
+-	print 'Data...',data
++	print('Data...',data)
+ 	
+ 
+ ##############################################################
+@@ -587,7 +586,7 @@ def testOutputGrabber():
+ class AIObject:
+ 	"Base class for all AI objects"
+ 	def printAI(self):
+-		print '% base AI object'
++		print('% base AI object')
+ 	
+ 		
+ class AILiteral(AIObject):
+@@ -595,7 +594,7 @@ class AILiteral(AIObject):
+ 	def __init__(self, text):
+ 		self.text = text
+ 	def printAI(self):
+-		print self.text
++		print(self.text)
+ 
+ 
+ 
+@@ -608,7 +607,7 @@ class AICatalog(AIObject):
+ /Outlines %d 0 R
+ >>'''
+ 	def printAI(self):
+-		print self.template % (self.RefPages, self.RefOutlines)
++		print(self.template % (self.RefPages, self.RefOutlines))
+ 
+ class AIHeader(AIObject):
+ 	# no features implemented yet
+@@ -622,26 +621,26 @@ class AIHeader(AIObject):
+ 		self.datestr = time.strftime("%x %I:%M %p", now)
+ 				
+ 	def printAI(self):
+-		print "%!PS-Adobe-3.0"
+-		print "%%Creator: PIDDLE Adobe Illustrator backend"
+-		print "%%Title: " +'(%s)' % self.title
+-		print "%%For: " +'(%s)' % self.author
+-		print "%%CreationDate: " +'(%s)' % self.datestr
+-		print "%%DocumentProcessColors: Black"""
+-		print '%%BoundingBox: ' + '%s %s %s %s' % self.boundingBox
++		print("%!PS-Adobe-3.0")
++		print("%%Creator: PIDDLE Adobe Illustrator backend")
++		print("%%Title: " +'(%s)' % self.title)
++		print("%%For: " +'(%s)' % self.author)
++		print("%%CreationDate: " +'(%s)' % self.datestr)
++		print("%%DocumentProcessColors: Black""")
++		print('%%BoundingBox: ' + '%s %s %s %s' % self.boundingBox)
+ 		#%%DocumentProcessColors: Cyan Magenta Yellow
+ 		#%%DocumentCustomColors: (PANTONE 156 CV)
+ 		#%%RGBCustomColor: red green blue (customcolorname)
+ 		#%%DocumentFonts: CooperBlack
+ 		#%%+ Minion-Regular
+ 		#%%DocumentFiles: WrathOfRalph
+-		print "%AI5_FileFormat 3"
+-		print "%AI3_ColorUsage: Color"
+-		print '%AI5_ArtSize: ' + '%s %s' % self.pagesize
+-		print '%AI5_Templatebox: ' + '%s %s' % self.pagesize
++		print("%AI5_FileFormat 3")
++		print("%AI3_ColorUsage: Color")
++		print('%AI5_ArtSize: ' + '%s %s' % self.pagesize)
++		print('%AI5_Templatebox: ' + '%s %s' % self.pagesize)
+ 		#%AI7_ImageSettings: flag
+-		print '%AI5_TargetResolution: 300'
+-		print '%%EndComments'		
++		print('%AI5_TargetResolution: 300')
++		print('%%EndComments')		
+ 
+ 
+ class AIProlog(AIObject):
+@@ -649,18 +648,18 @@ class AIProlog(AIObject):
+ 	def __init__(self):
+ 		self.FontList = []
+ 	def printAI(self):
+-		print '%%BeginProlog'
+-		print '%%EndProlog'
++		print('%%BeginProlog')
++		print('%%EndProlog')
+ 
+ class AISetUp(AIObject):
+ 	"null outline, does nothing yet"
+ 	def __init__(self):
+ 		self.FontList = []
+ 	def printAI(self):
+-		print '%%BeginSetup'
++		print('%%BeginSetup')
+ 		if self.FontList:
+ 			pass
+-		print '%%EndSetup'
++		print('%%EndSetup')
+ 	
+ class AIPageCollection(AIObject):
+ 	"presumes PageList attribute set (list of integers)"
+@@ -671,7 +670,7 @@ class AIPageCollection(AIObject):
+ 		for page in self.PageList:
+ 			result = result + str(page) + ' 0 R '
+ 		result = result + ']\n>>'
+-		print result
++		print(result)
+ 
+ #class AIBody(AIObject):
+ #	"""The Bastard.  Needs list of Resources etc. Use a standard one for now.
+@@ -776,14 +775,14 @@ class AIStream(AIObject):
+ 
+ 			
+ #		print '<< /Length %d >>' % length
+-		print '''%AI5_BeginLayer
++		print('''%AI5_BeginLayer
+ 1 1 1 1 0 0 0 79 128 255 Lb
+-(Foreground) Ln'''
+-		print self.transformAI(self.originx, self.originy, self.height)
++(Foreground) Ln''')
++		print(self.transformAI(self.originx, self.originy, self.height))
+ 
+ #		print 'XXXX', self.data
+-		print '''LB
+-%AI5_EndLayer--'''
++		print('''LB
++%AI5_EndLayer--''')
+ 
+ 	def transformAI(self, ox, oy, ty):
+ #		print 'transformAI', ox, oy
+@@ -806,7 +805,7 @@ class AIStream(AIObject):
+ 			
+ class AIImage(AIObject):
+ 	def printAI(self):
+-		print """<<
++		print("""<<
+ /Type /XObject
+ /Subtype /Image
+ /Name /Im0
+@@ -823,7 +822,7 @@ stream
+ B2BBC2 BB6F84 31BFC2 18EA3C 0E3E00 07FC00 03F800
+ 1E1800 1FF800>
+ endstream
+-endobj"""
++endobj""")
+ 			
+ class AIType1Font(AIObject):
+ 	def __init__(self, key, font):
+@@ -837,11 +836,11 @@ class AIType1Font(AIObject):
+ /Encoding /WinAnsiEncoding
+ >>"""
+ 	def printAI(self):
+-		print self.template % (self.keyname, self.fontname)
++		print(self.template % (self.keyname, self.fontname))
+ 
+ class AIProcSet(AIObject):
+ 	def printAI(self):
+-		print "[/AI /Text]"
++		print("[/AI /Text]")
+ 
+ 
+ 
+@@ -876,4 +875,4 @@ def MakeFontDictionary(startpos, count):
+ 	
+ 
+ #if __name__ == '__main__':
+-#	print 'For test scripts, run test1.py to test7.py'
+\ No newline at end of file
++#	print 'For test scripts, run test1.py to test7.py'
+--- src/piddle/discipline.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/discipline.py
+@@ -4,28 +4,28 @@ from piddle import *
+ def checkMethods(parentMethod, childMethod):
+ 	"Make sure the child's method obey's the parent's interface; return 1 if OK."
+ 	# get the parameter names
+-	pf = parentMethod.func_code
+-	cf = childMethod.func_code
++	pf = parentMethod.__code__
++	cf = childMethod.__code__
+ 	pargs = pf.co_varnames[:pf.co_argcount]
+ 	cargs = cf.co_varnames[:cf.co_argcount]
+ 	
+ 	# make sure they match, at least as far as the parent's go
+ 	if len(cargs) < len(pargs):
+-		print "too few args"
++		print("too few args")
+ 		return 0	
+ 	for i in range(len(pargs)):
+ 		if pargs[i] != cargs[i]:
+-			print "arg names don't match"
++			print("arg names don't match")
+ 			return 0
+ 
+ 	# if child has any additional arguments, make sure
+ 	# they have default values
+ 	extras = len(cargs) - len(pargs)
+-	defs = childMethod.func_defaults
++	defs = childMethod.__defaults__
+ 	if extras and (defs is None or len(defs) < extras):
+-		print "need %s defaults, got %s" % (extras, defs)
+-		print cargs
+-		print pargs
++		print("need %s defaults, got %s" % (extras, defs))
++		print(cargs)
++		print(pargs)
+ 		return 0
+ 	
+ 	# otherwise, it's OK
+@@ -41,17 +41,17 @@ def checkClasses(parent, child):
+ 		if type(item) != MethodType or name[0] == '_':
+ 			pass  # print "     %s is not a public method" % name
+ 		elif name in parentDir:
+-			if not checkMethods(getattr(parent, name).im_func, item.im_func):
+-				print "NAUGHTY CHILD disobeys arguments to", name
++			if not checkMethods(getattr(parent, name).__func__, item.__func__):
++				print("NAUGHTY CHILD disobeys arguments to", name)
+ 			else:
+-				print "     %s looks OK" % name
++				print("     %s looks OK" % name)
+ 		else:
+-			print "     %s is unique to the child" % name
++			print("     %s is unique to the child" % name)
+ 
+-foo = raw_input("backend to check (e.g., PDF):")
++foo = input("backend to check (e.g., PDF):")
+ if foo:
+ 	canvasname = foo+"Canvas"
+ 	module = __import__("piddle"+foo, globals(), locals(), [canvasname] )
+ 	child = getattr(module, canvasname)
+-	print "\nChecking %s...\n" % canvasname
++	print("\nChecking %s...\n" % canvasname)
+ 	checkClasses( Canvas, child )
+--- src/piddle/pdfdoc.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/pdfdoc.py
+@@ -18,7 +18,7 @@ import sys
+ import string
+ import time
+ import tempfile
+-import cStringIO
++import io
+ from types import *
+ from math import sin, cos, pi, ceil
+ 
+@@ -152,10 +152,10 @@ class PDFDocument:
+ 
+     
+     def printTrailer(self):
+-        print 'trailer'
+-        print '<< /Size %d /Root %d 0 R /Info %d 0 R>>' % (len(self.objects) + 1, 1, self.infopos)
+-        print 'startxref'
+-        print self.startxref
++        print('trailer')
++        print(('<< /Size %d /Root %d 0 R /Info %d 0 R>>' % (len(self.objects) + 1, 1, self.infopos)))
++        print('startxref')
++        print((self.startxref))
+ 
+     def writeTrailer(self, f):
+         f.write('trailer' + LINEEND)
+@@ -176,7 +176,6 @@ class PDFDocument:
+         i = 1
+         self.xref = []
+         f.write("%PDF-1.2" + LINEEND)  # for CID support
+-        f.write("%í춾" + LINEEND)
+         for obj in self.objects:
+             pos = f.tell()
+             self.xref.append(pos)
+@@ -201,20 +200,19 @@ class PDFDocument:
+ 
+     def printPDF(self):
+         "prints it to standard output.  Logs positions for doing trailer"
+-        print "%PDF-1.0"
+-        print "%í춾"
++        print("%PDF-1.0")
+         i = 1
+         self.xref = []
+         for obj in self.objects:
+             pos = sys.stdout.tell()
+             self.xref.append(pos)
+-            print i, '0 obj'
++            print(i, '0 obj')
+             obj.printPDF()
+-            print 'endobj'
++            print('endobj')
+             i = i + 1
+         self.printXref()
+         self.printTrailer()
+-        print "%%EOF",
++        print("%%EOF", end=' ')
+ 
+     def addPage(self, page):
+         """adds page and stream at end.  Maintains pages list"""
+@@ -235,16 +233,16 @@ class PDFDocument:
+         #self.objects.append(page.stream)
+ 
+     def hasFont(self, psfontname):
+-        return self.fontMapping.has_key(psfontname)
++        return psfontname in self.fontMapping
+ 
+     def getInternalFontName(self, psfontname):
+         try:
+             return self.fontMapping[psfontname]
+         except:
+-            raise PDFError, "Font %s not available in document" % psfontname
++            raise PDFError("Font %s not available in document" % psfontname)
+ 
+     def getAvailableFonts(self):
+-        fontnames = self.fontMapping.keys()
++        fontnames = list(self.fontMapping.keys())
+         fontnames.sort()
+         return fontnames
+     
+@@ -284,10 +282,10 @@ class OutputGrabber:
+ def testOutputGrabber():
+     gr = OutputGrabber()
+     for i in range(10):
+-        print 'line',i
++        print('line',i)
+     data = gr.getData()
+     gr.close()
+-    print 'Data...',data
++    print('Data...',data)
+     
+ 
+ ##############################################################
+@@ -562,4 +560,4 @@ def MakeFontDictionary(startpos, count):
+     return dict
+         
+ if __name__ == '__main__':
+-    print 'For test scripts, run test1.py to test6.py'
++    print('For test scripts, run test1.py to test6.py')
+--- src/piddle/pdfgen.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/pdfgen.py
+@@ -53,7 +53,7 @@ import sys
+ import string
+ import time
+ import tempfile
+-import cStringIO
++import io
+ from types import *
+ from math import sin, cos, tan, pi, ceil
+ 
+@@ -570,12 +570,12 @@ class Canvas:
+         try: 
+             import Image
+         except ImportError:
+-            print 'Python Imaging Library not available'
++            print('Python Imaging Library not available')
+             return
+         try:
+             import zlib
+         except ImportError:
+-            print 'zlib not available'
++            print('zlib not available')
+             return
+             
+         self._currentPageHasImages = 1
+@@ -605,9 +605,9 @@ class Canvas:
+                 #write in blocks of (??) 60 characters per line to a list
+                 compressed = imageFile.read()
+                 encoded = pdfutils._AsciiBase85Encode(compressed)
+-                outstream = cStringIO.StringIO(encoded)
++                outstream = io.StringIO(encoded)
+                 dataline = outstream.read(60)
+-                while dataline <> "":
++                while dataline != "":
+                     imagedata.append(dataline)
+                     dataline = outstream.read(60)
+                 imagedata.append('EI')
+@@ -618,7 +618,7 @@ class Canvas:
+                 cachedname = os.path.splitext(image)[0] + '.a85'
+                 imagedata = open(cachedname,'rb').readlines()
+                 #trim off newlines...
+-                imagedata = map(string.strip, imagedata)
++                imagedata = list(map(string.strip, imagedata))
+                 
+                 #parse line two for width, height
+                 words = string.split(imagedata[1])
+@@ -643,9 +643,9 @@ class Canvas:
+             encoded = pdfutils._AsciiBase85Encode(compressed) #...sadly this isn't
+ 
+             #write in blocks of (??) 60 characters per line to a list
+-            outstream = cStringIO.StringIO(encoded)
++            outstream = io.StringIO(encoded)
+             dataline = outstream.read(60)
+-            while dataline <> "":
++            while dataline != "":
+                 imagedata.append(dataline)
+                 dataline = outstream.read(60)
+             imagedata.append('EI')
+@@ -680,48 +680,48 @@ class Canvas:
+     # This is based on Thomas Merz's code from GhostScript (viewjpeg.ps)
+     def readJPEGInfo(self, image):
+         "Read width, height and number of components from JPEG file"
+-    	import struct
++        import struct
+ 
+-	#Acceptable JPEG Markers:
+-	#  SROF0=baseline, SOF1=extended sequential or SOF2=progressive
+-	validMarkers = [0xC0, 0xC1, 0xC2]
++        #Acceptable JPEG Markers:
++        #  SROF0=baseline, SOF1=extended sequential or SOF2=progressive
++        validMarkers = [0xC0, 0xC1, 0xC2]
+ 
+-	#JPEG markers without additional parameters
+-	noParamMarkers = \
+-	    [ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01 ]
++        #JPEG markers without additional parameters
++        noParamMarkers = \
++            [ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01 ]
+ 
+-	#Unsupported JPEG Markers
+-	unsupportedMarkers = \
+-	    [ 0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF ]
++        #Unsupported JPEG Markers
++        unsupportedMarkers = \
++            [ 0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF ]
+ 
+-	#read JPEG marker segments until we find SOFn marker or EOF
+-	done = 0
+-	while not done:
+-	    x = struct.unpack('B', image.read(1))
+-	    if x[0] == 0xFF:			#found marker
+-	    	x = struct.unpack('B', image.read(1))
+-		#print "Marker: ", '%0.2x' % x[0]
+-		#check marker type is acceptable and process it
+-		if x[0] in validMarkers:
+-		    image.seek(2, 1)		#skip segment length
+-		    x = struct.unpack('B', image.read(1)) #data precision
+-		    if x[0] != 8:
+-			raise 'PDFError', ' JPEG must have 8 bits per component'
+-		    y = struct.unpack('BB', image.read(2))
+-		    height = (y[0] << 8) + y[1] 
+-		    y = struct.unpack('BB', image.read(2))
+-		    width =  (y[0] << 8) + y[1]
+-		    y = struct.unpack('B', image.read(1))
+-		    color =  y[0]
+-		    return width, height, color
+-		    done = 1
+-		elif x[0] in unsupportedMarkers:
+-		    raise 'PDFError', ' Unsupported JPEG marker: %0.2x' % x[0]
+-		elif x[0] not in noParamMarkers:
+-		    #skip segments with parameters
+-		    #read length and skip the data
+-		    x = struct.unpack('BB', image.read(2))
+-		    image.seek( (x[0] << 8) + x[1] - 2, 1)	
++        #read JPEG marker segments until we find SOFn marker or EOF
++        done = 0
++        while not done:
++            x = struct.unpack('B', image.read(1))
++            if x[0] == 0xFF:    #found marker
++                x = struct.unpack('B', image.read(1))
++                #print "Marker: ", '%0.2x' % x[0]
++                #check marker type is acceptable and process it
++                if x[0] in validMarkers:
++                    image.seek(2, 1)    #skip segment length
++                    x = struct.unpack('B', image.read(1)) #data precision
++                    if x[0] != 8:
++                        raise('PDFError', ' JPEG must have 8 bits per component')
++                    y = struct.unpack('BB', image.read(2))
++                    height = (y[0] << 8) + y[1] 
++                    y = struct.unpack('BB', image.read(2))
++                    width =  (y[0] << 8) + y[1]
++                    y = struct.unpack('B', image.read(1))
++                    color =  y[0]
++                    return width, height, color
++                    done = 1
++                elif x[0] in unsupportedMarkers:
++                    raise('PDFError', ' Unsupported JPEG marker: %0.2x' % x[0])
++                elif x[0] not in noParamMarkers:
++                    #skip segments with parameters
++                    #read length and skip the data
++                    x = struct.unpack('BB', image.read(2))
++                    image.seek((x[0] << 8) + x[1] - 2, 1)
+ 
+     def setPageCompression(self, onoff=1):
+         """Possible values 1 or 0 (1 for 'on' is the default).
+@@ -763,17 +763,17 @@ class Canvas:
+         if direction in [0,90,180,270]:
+             direction_arg = '/Di /%d' % direction
+         else:
+-            raise 'PDFError', ' directions allowed are 0,90,180,270'
++            raise('PDFError', ' directions allowed are 0,90,180,270')
+         
+         if dimension in ['H', 'V']:
+             dimension_arg = '/Dm /%s' % dimension
+         else:
+-            raise'PDFError','dimension values allowed are H and V'
++            raise('PDFError','dimension values allowed are H and V')
+         
+         if motion in ['I','O']:
+             motion_arg = '/M /%s' % motion
+         else:
+-            raise'PDFError','motion values allowed are I and O'
++            raise('PDFError','motion values allowed are I and O')
+ 
+ 
+         # this says which effects require which argument types from above
+@@ -789,7 +789,7 @@ class Canvas:
+         try:
+             args = PageTransitionEffects[effectname]
+         except KeyError:
+-            raise 'PDFError', 'Unknown Effect Name "%s"' % effectname
++            raise('PDFError', 'Unknown Effect Name "%s"' % effectname)
+             self._pageTransitionString = ''
+             return
+         
+@@ -1033,7 +1033,7 @@ class PDFTextObject:
+         if type(stuff) == StringType:
+             lines = string.split(string.strip(stuff), '\n')
+             if trim==1:
+-                lines = map(string.strip,lines)
++                lines = list(map(string.strip,lines))
+         elif type(stuff) == ListType:
+             lines = stuff
+         elif type(stuff) == TupleType:
+@@ -1055,4 +1055,4 @@ class PDFTextObject:
+ 
+ 
+ if __name__ == '__main__':
+-    print 'For test scripts, run testpdfgen.py'
++    print('For test scripts, run testpdfgen.py')
+--- src/piddle/pdfgeom.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/pdfgeom.py
+@@ -10,7 +10,7 @@ So far, just Robert Kern's bezierArc.
+ from math import sin, cos, pi, ceil
+ 
+ def bezierArc(x1,y1, x2,y2, startAng=0, extent=90):
+-    """bezierArc(x1,y1, x2,y2, startAng=0, extent=90) --> List of BÈzier
++    """bezierArc(x1,y1, x2,y2, startAng=0, extent=90) --> List of Bezier
+ curve control points.
+ 
+ (x1, y1) and (x2, y2) are the corners of the enclosing rectangle.  The
+@@ -22,7 +22,7 @@ semi-circle.
+ 
+ The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4)
+ such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and
+-(x3, y3) as their respective BÈzier control points."""
++(x3, y3) as their respective Bezier control points."""
+ 
+     x1,y1, x2,y2 = min(x1,x2), max(y1,y2), max(x1,x2), min(y1,y2)
+ 
+--- src/piddle/pdfmetrics.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/pdfmetrics.py
+@@ -93,7 +93,7 @@ class FontCache:
+         
+     def loadfont(self, fontname):
+         filename = AFMDIR + os.sep + fontname + '.afm'
+-        print 'cache loading',filename
++        print('cache loading',filename)
+         assert os.path.exists(filename)
+         widths = parseAFMfile(filename)
+         self.__widtharrays[fontname] = widths
+@@ -107,7 +107,7 @@ class FontCache:
+                 return self.__widtharrays[fontname]
+             except:
+                 # font not found, use Courier
+-                print 'Font',fontname,'not found - using Courier for widths'
++                print('Font',fontname,'not found - using Courier for widths')
+                 return self.getfont('courier')
+     
+ 
+@@ -120,7 +120,7 @@ class FontCache:
+ 
+     def status(self):
+         #returns loaded fonts
+-        return self.__widtharrays.keys()
++        return list(self.__widtharrays.keys())
+         
+ TheFontCache = FontCache()
+ 
+--- src/piddle/pdfutils.py.orig	2002-06-03 13:46:30 UTC
++++ src/piddle/pdfutils.py
+@@ -3,7 +3,7 @@
+ 
+ import os
+ import string
+-import cStringIO
++import io
+ 
+ LINEEND = '\015\012'
+ 
+@@ -32,9 +32,9 @@ def cacheImageFile(filename):
+     encoded = _AsciiBase85Encode(compressed) #...sadly this isn't
+     
+     #write in blocks of 60 characters per line
+-    outstream = cStringIO.StringIO(encoded)
++    outstream = io.StringIO(encoded)
+     dataline = outstream.read(60)
+-    while dataline <> "":
++    while dataline != "":
+         code.append(dataline)
+         dataline = outstream.read(60)
+     
+@@ -45,7 +45,7 @@ def cacheImageFile(filename):
+     f = open(cachedname,'wb')
+     f.write(string.join(code, LINEEND)+LINEEND)
+     f.close()
+-    print 'cached image as %s' % cachedname
++    print('cached image as %s' % cachedname)
+ 
+ 
+ def preProcessImages(spec):
+@@ -54,14 +54,14 @@ def preProcessImages(spec):
+     to save huge amounts of time when repeatedly building image
+     documents."""
+     import types
+-    if type(spec) is types.StringType:
++    if type(spec) is bytes:
+         filelist = glob.glob(spec)
+     else:  #list or tuple OK
+         filelist = spec
+ 
+     for filename in filelist:
+         if cachedImageExists(filename):
+-            print 'cached version of %s already exists' % filename
++            print('cached version of %s already exists' % filename)
+         else:
+             cacheImageFile(filename)
+         
+@@ -111,7 +111,7 @@ def _AsciiHexEncode(input):
+     """This is a verbose encoding used for binary data within
+     a PDF file.  One byte binary becomes two bytes of ASCII."""
+     "Helper function used by images"
+-    output = cStringIO.StringIO()
++    output = io.StringIO()
+     for char in input:
+         output.write('%02x' % ord(char))
+     output.write('>')
+@@ -126,7 +126,7 @@ def _AsciiHexDecode(input):
+     stripped = stripped[:-1]  #chop off terminator
+     assert len(stripped) % 2 == 0, 'Ascii Hex stream has odd number of bytes'
+     i = 0
+-    output = cStringIO.StringIO()
++    output = io.StringIO()
+     while i < len(stripped):
+         twobytes = stripped[i:i+2]
+         output.write(chr(eval('0x'+twobytes)))
+@@ -136,21 +136,21 @@ def _AsciiHexDecode(input):
+ 
+ def _AsciiHexTest(text='What is the average velocity of a sparrow?'):
+     "Do the obvious test for whether Ascii Hex encoding works"
+-    print 'Plain text:', text
++    print('Plain text:', text)
+     encoded = _AsciiHexEncode(text)
+-    print 'Encoded:', encoded
++    print('Encoded:', encoded)
+     decoded = _AsciiHexDecode(encoded)
+-    print 'Decoded:', decoded
++    print('Decoded:', decoded)
+     if decoded == text:
+-        print 'Passed'
++        print('Passed')
+     else:
+-        print 'Failed!'
++        print('Failed!')
+     
+ def _AsciiBase85Encode(input):
+     """This is a compact encoding used for binary data within
+     a PDF file.  Four bytes of binary data become five bytes of
+     ASCII.  This is the default method used for encoding images."""
+-    outstream = cStringIO.StringIO()
++    outstream = io.StringIO()
+     # special rules apply if not a multiple of four bytes.  
+     whole_word_count, remainder_size = divmod(len(input), 4)
+     cut = 4 * whole_word_count
+@@ -163,7 +163,7 @@ def _AsciiBase85Encode(input):
+         b3 = ord(body[offset+2])
+         b4 = ord(body[offset+3])
+     
+-        num = 16777216L * b1 + 65536 * b2 + 256 * b3 + b4
++        num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4
+ 
+         if num == 0:
+             #special case
+@@ -194,7 +194,7 @@ def _AsciiBase85Encode(input):
+         b3 = ord(lastbit[2])
+         b4 = ord(lastbit[3])
+ 
+-        num = 16777216L * b1 + 65536 * b2 + 256 * b3 + b4
++        num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4
+ 
+         #solve for c1..c5
+         temp, c5 = divmod(num, 85)
+@@ -217,7 +217,7 @@ def _AsciiBase85Encode(input):
+ def _AsciiBase85Decode(input):
+     """This is not used - Acrobat Reader decodes for you - but a round
+     trip is essential for testing."""
+-    outstream = cStringIO.StringIO()
++    outstream = io.StringIO()
+     #strip all whitespace
+     stripped = string.join(string.split(input),'')
+     #check end
+@@ -229,7 +229,7 @@ def _AsciiBase85Decode(input):
+     # special rules apply if not a multiple of five bytes.  
+     whole_word_count, remainder_size = divmod(len(stripped), 5)
+     #print '%d words, %d leftover' % (whole_word_count, remainder_size)
+-    assert remainder_size <> 1, 'invalid Ascii 85 stream!'
++    assert remainder_size != 1, 'invalid Ascii 85 stream!'
+     cut = 5 * whole_word_count
+     body, lastbit = stripped[0:cut], stripped[cut:]
+     
+@@ -301,14 +301,14 @@ def _wrap(input, columns=60):
+ 
+ def _AsciiBase85Test(text='What is the average velocity of a sparrow?'):
+     "Do the obvious test for whether Base 85 encoding works"
+-    print 'Plain text:', text
++    print('Plain text:', text)
+     encoded = _AsciiBase85Encode(text)
+-    print 'Encoded:', encoded
++    print('Encoded:', encoded)
+     decoded = _AsciiBase85Decode(encoded)
+-    print 'Decoded:', decoded
++    print('Decoded:', decoded)
+     if decoded == text:
+-        print 'Passed'
++        print('Passed')
+     else:
+-        print 'Failed!'
++        print('Failed!')
+ 
+ 
+--- src/piddle/piddle.py.orig	2002-06-03 13:48:50 UTC
++++ src/piddle/piddle.py
+@@ -143,7 +143,7 @@ class Color:
+ 		d["blue"] = _float(blue)
+ 
+ 	def __setattr__(self, name, value):
+-		raise TypeError, "piddle.Color has read-only attributes"
++		raise TypeError("piddle.Color has read-only attributes")
+ 
+ 	def __mul__(self,x):
+ 		return Color(self.red*x, self.green*x, self.blue*x)
+@@ -369,7 +369,7 @@ class Font:
+                                          self.underline, repr(self.face))
+ 
+     def __setattr__(self, name, value):
+-        raise TypeError, "piddle.Font has read-only attributes"
++        raise TypeError("piddle.Font has read-only attributes")
+ 
+ 
+ #-------------------------------------------------------------------------
+@@ -453,25 +453,23 @@ class Canvas:
+                 but which might be buffered should be flushed to the screen"
+ 		pass
+ 
+-        def save(self, file=None, format=None):
++	def save(self, file=None, format=None):
+ 
+-                """For backends that can be save to a file or sent to a
+-                stream, create a valid file out of what's currently been
+-                drawn on the canvas.  Trigger any finalization here.
+-                Though some backends may allow further drawing after this call,
+-                presume that this is not possible for maximum portability
++		"""For backends that can be save to a file or sent to a
++		stream, create a valid file out of what's currently been
++		drawn on the canvas.  Trigger any finalization here.
++		Though some backends may allow further drawing after this call,
++		presume that this is not possible for maximum portability
+ 
+-                file may be either a string or a file object with a write method
+-                     if left as the default, the canvas's current name will be used
++		file may be either a string or a file object with a write method
++		     if left as the default, the canvas's current name will be used
+ 
+-                format may be used to specify the type of file format to use as
+-                     well as any corresponding extension to use for the filename
+-                     This is an optional argument and backends may ignore it if
+-                     they only produce one file format."""
+-                pass 
++		format may be used to specify the type of file format to use as
++		     well as any corresponding extension to use for the filename
++		     This is an optional argument and backends may ignore it if
++		     they only produce one file format."""
++		pass 
+ 
+-                                
+-	
+ 	def setInfoLine(self, s):
+ 		"For interactive Canvases, displays the given string in the \
+ 		'info line' somewhere where the user can probably see it."
+@@ -481,7 +479,7 @@ class Canvas:
+ 	def stringWidth(self, s, font=None):
+ 		"Return the logical width of the string if it were drawn \
+ 		in the current font (defaults to self.font)."
+-		raise NotImplementedError, 'stringWidth'
++		raise NotImplementedError('stringWidth')
+ 	
+ 	def fontHeight(self, font=None):
+ 		"Find the height of one line of text (baseline to baseline) of the given font."
+@@ -492,11 +490,11 @@ class Canvas:
+ 		
+ 	def fontAscent(self, font=None):
+ 		"Find the ascent (height above base) of the given font."
+-		raise NotImplementedError, 'fontAscent'
++		raise NotImplementedError('fontAscent')
+ 	
+ 	def fontDescent(self, font=None):
+ 		"Find the descent (extent below base) of the given font."
+-		raise NotImplementedError, 'fontDescent'		
++		raise NotImplementedError('fontDescent')
+ 		
+ 	#------------- drawing helpers --------------
+ 
+@@ -602,7 +600,7 @@ class Canvas:
+ 
+ 	def drawLine(self, x1,y1, x2,y2, color=None, width=None):
+ 		"Draw a straight line between x1,y1 and x2,y2."
+-		raise NotImplementedError, 'drawLine'
++		raise NotImplementedError('drawLine')
+ 	
+ 	def drawLines(self, lineList, color=None, width=None):
+ 		"Draw a set of lines of uniform color and width.  \
+@@ -617,7 +615,7 @@ class Canvas:
+ 	def drawString(self, s, x,y, font=None, color=None, angle=0):
+ 		"Draw a string starting at location x,y."
+ 		# NOTE: the baseline goes on y; drawing covers (y-ascent,y+descent)
+-		raise NotImplementedError, 'drawString'
*** 1274 LINES SKIPPED ***