def testFontFileFailures(self): "Tests TTFontFile constructor error checks" self.assertRaises(TTFError, TTFontFile, "nonexistent file") self.assertRaises(TTFError, TTFontFile, getBytesIO(b"")) self.assertRaises(TTFError, TTFontFile, getBytesIO(b"invalid signature")) self.assertRaises(TTFError, TTFontFile, getBytesIO(b"OTTO - OpenType not supported yet")) self.assertRaises(TTFError, TTFontFile, getBytesIO(b"\0\1\0\0"))
def testFontFileChecksum(self): "Tests TTFontFile and TTF parsing code" F = TTFOpenFile("Vera.ttf")[1].read() TTFontFile(getBytesIO(F), validate=1) # should not fail F1 = F[:12345] + b"\xFF" + F[12346:] # change one byte self.assertRaises(TTFError, TTFontFile, getBytesIO(F1), validate=1) F1 = F[:8] + b"\xFF" + F[9:] # change one byte self.assertRaises(TTFError, TTFontFile, getBytesIO(F1), validate=1)
def saveAsHandout(self): """Write the PDF document, multiple slides per page.""" styleSheet = getSampleStyleSheet() h1 = styleSheet['Heading1'] bt = styleSheet['BodyText'] if self.sourceFilename : filename = os.path.splitext(self.sourceFilename)[0] + '.pdf' outfile = getBytesIO() doc = SimpleDocTemplate(outfile, pagesize=rl_config.defaultPageSize, showBoundary=0) doc.leftMargin = 1*cm doc.rightMargin = 1*cm doc.topMargin = 2*cm doc.bottomMargin = 2*cm multiPageWidth = rl_config.defaultPageSize[0] - doc.leftMargin - doc.rightMargin - 50 story = [] orgFullPageSize = (self.pageWidth, self.pageHeight) t = makeSlideTable(self.slides, orgFullPageSize, multiPageWidth, self.cols) story.append(t) ## #ensure outline visible by default ## if self.showOutline: ## doc.canv.showOutline() doc.build(story) return self.savetofile(outfile, filename)
def pygments2xpre(s, language="python"): "Return markup suitable for XPreformatted" try: from pygments import highlight from pygments.formatters import HtmlFormatter except ImportError: return s from pygments.lexers import get_lexer_by_name rconv = lambda x: x if isPy3: out = getStringIO() else: if isUnicode(s): s = asBytes(s) rconv = asUnicode out = getBytesIO() l = get_lexer_by_name(language) h = HtmlFormatter() highlight(s,l,h,out) styles = [(cls, style.split(';')[0].split(':')[1].strip()) for cls, (style, ttype, level) in h.class2style.items() if cls and style and style.startswith('color:')] return rconv(_2xpre(out.getvalue(),styles))
def smallArrow(): '''create a small PIL image''' from reportlab.graphics.renderPM import _getImage from reportlab.lib.utils import getBytesIO b = base64.decodestring(b'''R0lGODdhCgAHAIMAAP/////29v/d3f+ysv9/f/9VVf9MTP8iIv8ICP8AAAAAAAAAAAAAAAAAAAAA AAAAACwAAAAACgAHAAAIMwABCBxIsKABAQASFli4MAECAgEAJJhIceKBAQkyasx4YECBjx8TICAQ AIDJkwYEAFgZEAA7''') return _getImage().open(getBytesIO(b))
def testFontMaker(self): "Tests TTFontMaker class" ttf = TTFontMaker() ttf.add("ABCD", b"xyzzy") ttf.add("QUUX", b"123") ttf.add("head", b"12345678xxxx") stm = ttf.makeStream() ttf = TTFontParser(getBytesIO(stm), 0) self.assertEquals(ttf.get_table("ABCD"), b"xyzzy") self.assertEquals(ttf.get_table("QUUX"), b"123")
def _AsciiHexEncode(input): """Encodes input using ASCII-Hex coding. 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.""" if isUnicode(input): input = input.encode('utf-8') output = getBytesIO() output.write(binascii.b2a_hex(input)) output.write(b'>') return output.getvalue()
def saveAsPresentation(self): """Write the PDF document, one slide per page.""" if self.verbose: print('saving presentation...') pageSize = (self.pageWidth, self.pageHeight) if self.sourceFilename: filename = os.path.splitext(self.sourceFilename)[0] + '.pdf' if self.outDir: filename = os.path.join(self.outDir,os.path.basename(filename)) if self.verbose: print(filename) #canv = canvas.Canvas(filename, pagesize = pageSize) outfile = getBytesIO() if self.notes: #translate the page from landscape to portrait pageSize= pageSize[1], pageSize[0] canv = canvas.Canvas(outfile, pagesize = pageSize) canv.setPageCompression(self.compression) canv.setPageDuration(self.pageDuration) if self.title: canv.setTitle(self.title) if self.author: canv.setAuthor(self.author) if self.subject: canv.setSubject(self.subject) slideNo = 0 for slide in self.slides: #need diagnostic output if something wrong with XML slideNo = slideNo + 1 if self.verbose: print('doing slide %d, id = %s' % (slideNo, slide.id)) if self.notes: #frame and shift the slide #canv.scale(0.67, 0.67) scale_amt = (min(pageSize)/float(max(pageSize)))*.95 #canv.translate(self.pageWidth / 6.0, self.pageHeight / 3.0) #canv.translate(self.pageWidth / 2.0, .025*self.pageHeight) canv.translate(.025*self.pageHeight, (self.pageWidth/2.0) + 5) #canv.rotate(90) canv.scale(scale_amt, scale_amt) canv.rect(0,0,self.pageWidth, self.pageHeight) slide.drawOn(canv) canv.showPage() #ensure outline visible by default if self.showOutline: canv.showOutline() canv.save() return self.savetofile(outfile, filename)
def trySomeColors(C,enforceColorSpace=None): from reportlab.lib.utils import getBytesIO out=getBytesIO() canv = canvas.Canvas(out,enforceColorSpace=enforceColorSpace) canv.setFont('Helvetica',10) x = 0 y = 0 w,h = canv._pagesize for c in C: if y+10>h: y = 0 x += 10 canv.setFillColor(c) canv.rect(x,y,10,10,fill=1,stroke=0) y += 10 canv.showPage() canv.save()
def drawToString(d, showBoundary=rl_config.showBoundary, dviPreview='', title='Diagra EPS', company='ReportLab', dept='', preview=0): "Outputs the EPS to a string in memory" f = getBytesIO() drawToFile(d, f, dviPreview=dviPreview, title = title, dept = dept, company = company, preview = preview, showBoundary=showBoundary) return f.getvalue()
def trySomeColors(C, enforceColorSpace=None): from reportlab.lib.utils import getBytesIO out = getBytesIO() canv = canvas.Canvas(out, enforceColorSpace=enforceColorSpace) canv.setFont('Helvetica', 10) x = 0 y = 0 w, h = canv._pagesize for c in C: if y + 10 > h: y = 0 x += 10 canv.setFillColor(c) canv.rect(x, y, 10, 10, fill=1, stroke=0) y += 10 canv.showPage() canv.save()
def makeStream(self): "Finishes the generation and returns the TTF file as a string" stm = getBytesIO() write = stm.write numTables = len(self.tables) searchRange = 1 entrySelector = 0 while searchRange * 2 <= numTables: searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 16 rangeShift = numTables * 16 - searchRange # Header write( pack(">lHHHH", 0x00010000, numTables, searchRange, entrySelector, rangeShift)) # Table directory tables = list(self.tables.items()) tables.sort() # XXX is this the correct order? offset = 12 + numTables * 16 for tag, data in tables: if tag == 'head': head_start = offset checksum = calcChecksum(data) if isUnicodeType(tag): tag = tag.encode('utf-8') write(tag) write(pack(">LLL", checksum, offset, len(data))) paddedLength = (len(data) + 3) & ~3 offset = offset + paddedLength # Table data for tag, data in tables: data += b"\0\0\0" write(data[:len(data) & ~3]) checksum = calcChecksum(stm.getvalue()) checksum = add32(0xB1B0AFBA, -checksum) stm.seek(head_start + 8) write(pack('>L', checksum)) return stm.getvalue()
def drawToString(d, showBoundary=rl_config.showBoundary, dviPreview='', title='Diagra EPS', company='ReportLab', dept='', preview=0): "Outputs the EPS to a string in memory" f = getBytesIO() drawToFile(d, f, dviPreview=dviPreview, title=title, dept=dept, company=company, preview=preview, showBoundary=showBoundary) return f.getvalue()
def makeStream(self): "Finishes the generation and returns the TTF file as a string" stm = getBytesIO() write = stm.write numTables = len(self.tables) searchRange = 1 entrySelector = 0 while searchRange * 2 <= numTables: searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 16 rangeShift = numTables * 16 - searchRange # Header write(pack(">lHHHH", 0x00010000, numTables, searchRange, entrySelector, rangeShift)) # Table directory tables = list(self.tables.items()) tables.sort() # XXX is this the correct order? offset = 12 + numTables * 16 for tag, data in tables: if tag == 'head': head_start = offset checksum = calcChecksum(data) if isUnicodeType(tag): tag = tag.encode('utf-8') write(tag) write(pack(">LLL", checksum, offset, len(data))) paddedLength = (len(data)+3)&~3 offset = offset + paddedLength # Table data for tag, data in tables: data += b"\0\0\0" write(data[:len(data)&~3]) checksum = calcChecksum(stm.getvalue()) checksum = add32(0xB1B0AFBA, -checksum) stm.seek(head_start + 8) write(pack('>L', checksum)) return stm.getvalue()
def makeStream(self): "Finishes the generation and returns the TTF file as a string" stm = getBytesIO() write = stm.write tables = self.tables numTables = len(tables) searchRange = 1 entrySelector = 0 while searchRange * 2 <= numTables: searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 16 rangeShift = numTables * 16 - searchRange # Header write( pack(">lHHHH", 0x00010000, numTables, searchRange, entrySelector, rangeShift)) # Table directory offset = 12 + numTables * 16 wStr = (lambda x: write(bytes(tag, 'latin1'))) if isPy3 else write tables_items = list(sorted(tables.items())) for tag, data in tables_items: if tag == 'head': head_start = offset checksum = calcChecksum(data) wStr(tag) write(pack(">LLL", checksum, offset, len(data))) paddedLength = (len(data) + 3) & ~3 offset = offset + paddedLength # Table data for tag, data in tables_items: data += b"\0\0\0" write(data[:len(data) & ~3]) checksum = calcChecksum(stm.getvalue()) checksum = add32(0xB1B0AFBA, -checksum) stm.seek(head_start + 8) write(pack('>L', checksum)) return stm.getvalue()
def _preview(d,preview): '''create a device dependent preview image from drawing d''' from reportlab.graphics import renderPM if isinstance(preview,(int,float)): assert preview>0, "negative scaling is forbidden" g = d d = Drawing(g.width*preview, g.height*preview) g.transform = (preview,0,0,preview,0,0) #scale so it fits d.add(g) pilf = getBytesIO() transparent = getattr(g,'preview_transparent',None) or rl_config.eps_preview_transparent kwds = dict(fmt='TIFF') if transparent: configPIL = {} bg = configPIL['transparent'] = toColor(transparent) kwds['configPIL'] = configPIL kwds['bg'] = bg.int_rgb() renderPM.drawToFile(d,pilf,**kwds) return pilf.getvalue()
def makeStream(self): "Finishes the generation and returns the TTF file as a string" stm = getBytesIO() write = stm.write tables = self.tables numTables = len(tables) searchRange = 1 entrySelector = 0 while searchRange * 2 <= numTables: searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 16 rangeShift = numTables * 16 - searchRange # Header write(pack(">lHHHH", 0x00010000, numTables, searchRange, entrySelector, rangeShift)) # Table directory offset = 12 + numTables * 16 wStr = (lambda x:write(bytes(tag,'latin1'))) if isPy3 else write tables_items = list(sorted(tables.items())) for tag, data in tables_items: if tag == 'head': head_start = offset checksum = calcChecksum(data) wStr(tag) write(pack(">LLL", checksum, offset, len(data))) paddedLength = (len(data)+3)&~3 offset = offset + paddedLength # Table data for tag, data in tables_items: data += b"\0\0\0" write(data[:len(data)&~3]) checksum = calcChecksum(stm.getvalue()) checksum = add32(0xB1B0AFBA, -checksum) stm.seek(head_start + 8) write(pack('>L', checksum)) return stm.getvalue()
def _preview(d, preview): '''create a device dependent preview image from drawing d''' from reportlab.graphics import renderPM if isinstance(preview, (int, float)): assert preview > 0, "negative scaling is forbidden" g = d d = Drawing(g.width * preview, g.height * preview) g.transform = (preview, 0, 0, preview, 0, 0) #scale so it fits d.add(g) pilf = getBytesIO() transparent = getattr(g, 'preview_transparent', None) or rl_config.eps_preview_transparent kwds = dict(fmt='TIFF') if transparent: configPIL = {} bg = configPIL['transparent'] = toColor(transparent) kwds['configPIL'] = configPIL kwds['bg'] = bg.int_rgb() renderPM.drawToFile(d, pilf, **kwds) return pilf.getvalue()
def encryptPdfInMemory(inputPDF, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): """accepts a PDF file 'as a byte array in memory'; return encrypted one. This is a high level convenience and does not touch the hard disk in any way. If you are encrypting the same file over and over again, it's better to use pageCatcher and cache the results.""" try: from rlextra.pageCatcher.pageCatcher import storeFormsInMemory, restoreFormsInMemory except ImportError: raise ImportError('''reportlab.lib.pdfencrypt.encryptPdfInMemory failed because rlextra cannot be imported. See https://www.reportlab.com/downloads''') (bboxInfo, pickledForms) = storeFormsInMemory(inputPDF, all=1, BBoxes=1) names = list(bboxInfo.keys()) firstPageSize = bboxInfo['PageForms0'][2:] #now make a new PDF document buf = getBytesIO() canv = Canvas(buf, pagesize=firstPageSize) # set a standard ID while debugging if CLOBBERID: canv._doc._ID = "[(xxxxxxxxxxxxxxxx)(xxxxxxxxxxxxxxxx)]" formNames = restoreFormsInMemory(pickledForms, canv) for formName in formNames: canv.setPageSize(bboxInfo[formName][2:]) canv.doForm(formName) canv.showPage() encryptCanvas(canv, userPassword, ownerPassword, canPrint, canModify, canCopy, canAnnotate, strength=strength) canv.save() return buf.getvalue()
def encryptPdfInMemory(inputPDF, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): """accepts a PDF file 'as a byte array in memory'; return encrypted one. This is a high level convenience and does not touch the hard disk in any way. If you are encrypting the same file over and over again, it's better to use pageCatcher and cache the results.""" try: from rlextra.pageCatcher.pageCatcher import storeFormsInMemory, restoreFormsInMemory except ImportError: raise ImportError('''reportlab.lib.pdfencrypt.encryptPdfInMemory failed because rlextra cannot be imported. See http://developer.reportlab.com''') (bboxInfo, pickledForms) = storeFormsInMemory(inputPDF, all=1, BBoxes=1) names = list(bboxInfo.keys()) firstPageSize = bboxInfo['PageForms0'][2:] #now make a new PDF document buf = getBytesIO() canv = Canvas(buf, pagesize=firstPageSize) # set a standard ID while debugging if CLOBBERID: canv._doc._ID = "[(xxxxxxxxxxxxxxxx)(xxxxxxxxxxxxxxxx)]" encryptCanvas(canv, userPassword, ownerPassword, canPrint, canModify, canCopy, canAnnotate, strength=strength) formNames = restoreFormsInMemory(pickledForms, canv) for formName in formNames: #need to extract page size in future canv.doForm(formName) canv.showPage() canv.save() return buf.getvalue()
def testSubsetting(self): "Tests TTFontFile and TTF parsing code" ttf = TTFontFile("Vera.ttf") subset = ttf.makeSubset([0x41, 0x42]) subset = TTFontFile(getBytesIO(subset), 0) for tag in ('cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'OS/2', 'post', 'cvt ', 'fpgm', 'glyf', 'loca', 'prep'): self.assert_(subset.get_table(tag)) subset.seek_table('loca') for n in range(4): pos = subset.read_ushort() # this is actually offset / 2 self.failIf(pos % 2 != 0, "glyph %d at +%d should be long aligned" % (n, pos * 2)) self.assertEquals(subset.name, b"BitstreamVeraSans-Roman") self.assertEquals(subset.flags, FF_SYMBOLIC) self.assertEquals(subset.italicAngle, 0.0) self.assertNear(subset.ascent,759.765625) self.assertNear(subset.descent,-240.234375) self.assertEquals(subset.capHeight, 759.765625) self.assertNear(subset.bbox, [-183.10546875, -235.83984375, 1287.109375, 928.22265625]) self.assertEquals(subset.stemV, 87)
def _showWidgetProperties(self, widget): """Dump all properties of a widget.""" props = widget.getProperties() keys = props.keys() keys.sort() lines = [] for key in keys: value = props[key] f = getBytesIO() pprint.pprint(value, f) value = f.getvalue()[:-1] valueLines = value.split('\n') for i in range(1, len(valueLines)): valueLines[i] = ' '*(len(key)+3) + valueLines[i] value = '\n'.join(valueLines) lines.append('%s = %s' % (key, value)) text = '\n'.join(lines) self.story.append(Paragraph("<i>Properties of Example Widget</i>", self.bt)) self.story.append(Paragraph("", self.bt)) self.story.append(Preformatted(text, self.code))
def _showWidgetProperties(self, widget): """Dump all properties of a widget.""" props = widget.getProperties() keys = props.keys() keys.sort() lines = [] for key in keys: value = props[key] # Method 3 f = getBytesIO() pprint.pprint(value, f) value = f.getvalue()[:-1] valueLines = value.split('\n') for i in range(1, len(valueLines)): valueLines[i] = ' '*(len(key)+3) + valueLines[i] value = '\n'.join(valueLines) lines.append('%s = %s' % (key, value)) text = '\n'.join(lines) self.outLines.append('<H3>Properties of Example Widget</H3>') self.outLines.append('<PRE>%s</PRE>' % text) self.outLines.append('')
def saveToString(self, fmt='GIF'): s = getBytesIO() self.saveToFile(s, fmt=fmt) return s.getvalue()
def drawToString(d, showBoundary=rl_config.showBoundary): "Returns a PS as a string in memory, without touching the disk" s = getBytesIO() drawToFile(d, s, showBoundary=showBoundary) return s.getvalue()
def drawToString(d, msg="", showBoundary=rl_config._unset_, autoSize=1): "Returns a PDF as a string in memory, without touching the disk" s = getBytesIO() drawToFile(d, s, msg=msg, showBoundary=showBoundary, autoSize=autoSize) return s.getvalue()
def drawToString(d,fmt='GIF', dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_): s = getBytesIO() drawToFile(d,s,fmt=fmt, dpi=dpi, bg=bg, configPIL=configPIL) return s.getvalue()
def saveToString(self,fmt='GIF'): s = getBytesIO() self.saveToFile(s,fmt=fmt) return s.getvalue()
def _drawImageLevel2(self, image, x1,y1, x2=None,y2=None): # Postscript Level2 version '''At present we're handling only PIL''' ### what sort of image are we to draw if image.mode=='L' : imBitsPerComponent = 8 imNumComponents = 1 myimage = image elif image.mode == '1': myimage = image.convert('L') imNumComponents = 1 myimage = image else : myimage = image.convert('RGB') imNumComponents = 3 imBitsPerComponent = 8 imwidth, imheight = myimage.size if not x2: x2 = imwidth + x1 if not y2: y2 = y1 + imheight drawwidth = x2 - x1 drawheight = y2 - y1 self.code.extend([ 'gsave', '%s %s translate' % (x1,-y1 - drawheight), # need to start are lower left of image '%s %s scale' % (drawwidth,drawheight)]) if imNumComponents == 3 : self.code_append('/DeviceRGB setcolorspace') elif imNumComponents == 1 : self.code_append('/DeviceGray setcolorspace') # create the image dictionary self.code_append(""" << /ImageType 1 /Width %d /Height %d %% dimensions of source image /BitsPerComponent %d""" % (imwidth, imheight, imBitsPerComponent) ) if imNumComponents == 1: self.code_append('/Decode [0 1]') if imNumComponents == 3: self.code_append('/Decode [0 1 0 1 0 1] %% decode color values normally') self.code.extend([ '/ImageMatrix [%s 0 0 %s 0 %s]' % (imwidth, -imheight, imheight), '/DataSource currentfile /ASCIIHexDecode filter', '>> % End image dictionary', 'image']) # after image operator just need to dump image dat to file as hexstring rawimage = myimage.tostring() hex_encoded = self._AsciiHexEncode(rawimage) # write in blocks of 78 chars per line outstream = getBytesIO(hex_encoded) dataline = outstream.read(78) while dataline != "": self.code_append(dataline) dataline= outstream.read(78) self.code_append('> % end of image data') # > is EOD for hex encoded filterfor clarity self.code_append('grestore') # return coordinates to normal
def _drawImageLevel1(self, image, x1, y1, x2=None,y2=None): # Postscript Level1 version available for fallback mode when Level2 doesn't work """drawImage(self,image,x1,y1,x2=None,y2=None) : If x2 and y2 are ommitted, they are calculated from image size. (x1,y1) is upper left of image, (x2,y2) is lower right of image in piddle coordinates.""" # For now let's start with 24 bit RGB images (following piddlePDF again) component_depth = 8 myimage = image.convert('RGB') imgwidth, imgheight = myimage.size if not x2: x2 = imgwidth + x1 if not y2: y2 = y1 + imgheight drawwidth = x2 - x1 drawheight = y2 - y1 #print 'Image size (%d, %d); Draw size (%d, %d)' % (imgwidth, imgheight, drawwidth, drawheight) # now I need to tell postscript how big image is # "image operators assume that they receive sample data from # their data source in x-axis major index order. The coordinate # of the lower-left corner of the first sample is (0,0), of the # second (1,0) and so on" -PS2 ref manual p. 215 # # The ImageMatrix maps unit squre of user space to boundary of the source image # # The CurrentTransformationMatrix (CTM) maps the unit square of # user space to the rect...on the page that is to receive the # image. A common ImageMatrix is [width 0 0 -height 0 height] # (for a left to right, top to bottom image ) # first let's map the user coordinates start at offset x1,y1 on page self.code.extend([ 'gsave', '%s %s translate' % (x1,-y1 - drawheight), # need to start are lower left of image '%s %s scale' % (drawwidth,drawheight), '/scanline %d 3 mul string def' % imgwidth # scanline by multiples of image width ]) # now push the dimensions and depth info onto the stack # and push the ImageMatrix to map the source to the target rectangle (see above) # finally specify source (PS2 pp. 225 ) and by exmample self.code.extend([ '%s %s %s' % (imgwidth, imgheight, component_depth), '[%s %s %s %s %s %s]' % (imgwidth, 0, 0, -imgheight, 0, imgheight), '{ currentfile scanline readhexstring pop } false 3', 'colorimage ' ]) # data source output--now we just need to deliver a hex encode # series of lines of the right overall size can follow # piddlePDF again rawimage = myimage.tostring() hex_encoded = self._AsciiHexEncode(rawimage) # write in blocks of 78 chars per line outstream = getBytesIO(hex_encoded) dataline = outstream.read(78) while dataline != "": self.code_append(dataline) dataline= outstream.read(78) self.code_append('% end of image data') # for clarity self.code_append('grestore') # return coordinates to normal
def _AsciiHexEncode(self, input): # also based on piddlePDF "Helper function used by images" output = getBytesIO() for char in input: output.write('%02x' % ord(char)) return output.getvalue()
def drawToString(d, msg="", showBoundary=rl_config._unset_,autoSize=1): "Returns a PDF as a string in memory, without touching the disk" s = getBytesIO() drawToFile(d, s, msg=msg, showBoundary=showBoundary,autoSize=autoSize) return s.getvalue()
def test10(self): "test open and read of a simple relative file" from reportlab.lib.utils import open_and_read, getBytesIO b = getBytesIO(_rel_open_and_read('../docs/images/Edit_Prefs.gif')) b = open_and_read(b)