# HG changeset patch
# User goldfinger
# Date 1265882986 18000
# Node ID 4775b4195b4bef570b6a43f48b8da93bfdd42150
# Parent b3d76ebf2fac10596f3aafc2c65e5d9c88e590d6
code pour la generation de captchas
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/.DS_Store
Binary file pycaptcha/.DS_Store has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/BUGS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/BUGS Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,7 @@
+Known bugs:
+
+- PersistentFactory() is almost certainly horrible at concurrent access
+- Tests are never invalidated with PersistentStorage(), as they aren't written back to the database
+- All files in Captcha/data are installed, including silly things like .svn directories and *~
+
+
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/COPYING
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/COPYING Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,19 @@
+Copyright (c) 2004 Micah Dowty
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/.DS_Store
Binary file pycaptcha/Captcha/.DS_Store has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Base.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Base.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,127 @@
+""" Captcha.Base
+
+Base class for all types of CAPTCHA tests. All tests have one or
+more solution, determined when the test is generated. Solutions
+can be any python object,
+
+All tests can be solved by presenting at least some preset number
+of correct solutions. Some tests may only have one solution and require
+one solution, but other tests may require N correct solutions of M
+possible solutions.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import random, string, time, shelve
+
+__all__ = ["BaseCaptcha", "Factory", "PersistentFactory"]
+
+
+def randomIdentifier(alphabet = string.ascii_letters + string.digits,
+ length = 24):
+ return "".join([random.choice(alphabet) for i in xrange(length)])
+
+
+class BaseCaptcha(object):
+ """Base class for all CAPTCHA tests"""
+ # Subclasses can override these to set the solution criteria
+ minCorrectSolutions = 1
+ maxIncorrectSolutions = 0
+
+ def __init__(self):
+ self.solutions = []
+ self.valid = True
+
+ # Each test has a unique identifier, used to refer to that test
+ # later, and a creation time so it can expire later.
+ self.id = randomIdentifier()
+ self.creationTime = time.time()
+
+ def addSolution(self, solution):
+ self.solutions.append(solution)
+
+ def testSolutions(self, solutions):
+ """Test whether the given solutions are sufficient for this CAPTCHA.
+ A given CAPTCHA can only be tested once, after that it is invalid
+ and always returns False. This makes random guessing much less effective.
+ """
+ if not self.valid:
+ return False
+ self.valid = False
+
+ numCorrect = 0
+ numIncorrect = 0
+
+ for solution in solutions:
+ if solution in self.solutions:
+ numCorrect += 1
+ else:
+ numIncorrect += 1
+
+ return numCorrect >= self.minCorrectSolutions and \
+ numIncorrect <= self.maxIncorrectSolutions
+
+
+class Factory(object):
+ """Creates BaseCaptcha instances on demand, and tests solutions.
+ CAPTCHAs expire after a given amount of time, given in seconds.
+ The default is 15 minutes.
+ """
+ def __init__(self, lifetime=60*15):
+ self.lifetime = lifetime
+ self.storedInstances = {}
+
+ def new(self, cls, *args, **kwargs):
+ """Create a new instance of our assigned BaseCaptcha subclass, passing
+ it any extra arguments we're given. This stores the result for
+ later testing.
+ """
+ self.clean()
+ inst = cls(*args, **kwargs)
+ self.storedInstances[inst.id] = inst
+ return inst
+
+ def get(self, id):
+ """Retrieve the CAPTCHA with the given ID. If it's expired already,
+ this will return None. A typical web application will need to
+ new() a CAPTCHA when generating an html page, then get() it later
+ when its images or sounds must be rendered.
+ """
+ return self.storedInstances.get(id)
+
+ def clean(self):
+ """Removed expired tests"""
+ expiredIds = []
+ now = time.time()
+ for inst in self.storedInstances.itervalues():
+ if inst.creationTime + self.lifetime < now:
+ expiredIds.append(inst.id)
+ for id in expiredIds:
+ del self.storedInstances[id]
+
+ def test(self, id, solutions):
+ """Test the given list of solutions against the BaseCaptcha instance
+ created earlier with the given id. Returns True if the test passed,
+ False on failure. In either case, the test is invalidated. Returns
+ False in the case of an invalid id.
+ """
+ self.clean()
+ inst = self.storedInstances.get(id)
+ if not inst:
+ return False
+ result = inst.testSolutions(solutions)
+ return result
+
+
+class PersistentFactory(Factory):
+ """A simple persistent factory, for use in CGI or multi-process environments
+ where the state must remain across python interpreter sessions.
+ This implementation uses the 'shelve' module.
+ """
+ def __init__(self, filename, lifetime=60*15):
+ Factory.__init__(self, lifetime)
+ self.storedInstances = shelve.open(filename)
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Base.pyc
Binary file pycaptcha/Captcha/Base.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/File.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/File.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,53 @@
+""" Captcha.File
+
+Utilities for finding and picking random files from our 'data' directory
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import os, random
+
+# Determine the data directory. This can be overridden after import-time if needed.
+dataDir = os.path.join(os.path.split(os.path.abspath(__file__))[0], "data")
+
+
+class RandomFileFactory(object):
+ """Given a list of files and/or directories, this picks a random file.
+ Directories are searched for files matching any of a list of extensions.
+ Files are relative to our data directory plus a subclass-specified base path.
+ """
+ extensions = []
+ basePath = "."
+
+ def __init__(self, *fileList):
+ self.fileList = fileList
+ self._fullPaths = None
+
+ def _checkExtension(self, name):
+ """Check the file against our given list of extensions"""
+ for ext in self.extensions:
+ if name.endswith(ext):
+ return True
+ return False
+
+ def _findFullPaths(self):
+ """From our given file list, find a list of full paths to files"""
+ paths = []
+ for name in self.fileList:
+ path = os.path.join(dataDir, self.basePath, name)
+ if os.path.isdir(path):
+ for content in os.listdir(path):
+ if self._checkExtension(content):
+ paths.append(os.path.join(path, content))
+ else:
+ paths.append(path)
+ return paths
+
+ def pick(self):
+ if self._fullPaths is None:
+ self._fullPaths = self._findFullPaths()
+ return random.choice(self._fullPaths)
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/File.pyc
Binary file pycaptcha/Captcha/File.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Backgrounds.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Backgrounds.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,95 @@
+""" Captcha.Visual.Backgrounds
+
+Background layers for visual CAPTCHAs
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha.Visual import Layer, Pictures
+import random, os
+import ImageDraw, Image
+
+
+class SolidColor(Layer):
+ """A solid color background. Very weak on its own, but good
+ to combine with other backgrounds.
+ """
+ def __init__(self, color="white"):
+ self.color = color
+
+ def render(self, image):
+ image.paste(self.color)
+
+
+class Grid(Layer):
+ """A grid of lines, with a given foreground color.
+ The size is given in pixels. The background is transparent,
+ so another layer (like SolidColor) should be put behind it.
+ """
+ def __init__(self, size=16, foreground="black"):
+ self.size = size
+ self.foreground = foreground
+ self.offset = (random.uniform(0, self.size),
+ random.uniform(0, self.size))
+
+ def render(self, image):
+ draw = ImageDraw.Draw(image)
+
+ for i in xrange(image.size[0] / self.size + 1):
+ draw.line( (i*self.size+self.offset[0], 0,
+ i*self.size+self.offset[0], image.size[1]), fill=self.foreground)
+
+ for i in xrange(image.size[0] / self.size + 1):
+ draw.line( (0, i*self.size+self.offset[1],
+ image.size[0], i*self.size+self.offset[1]), fill=self.foreground)
+
+
+class TiledImage(Layer):
+ """Pick a random image and a random offset, and tile the rendered image with it"""
+ def __init__(self, imageFactory=Pictures.abstract):
+ self.tileName = imageFactory.pick()
+ self.offset = (random.uniform(0, 1),
+ random.uniform(0, 1))
+
+ def render(self, image):
+ tile = Image.open(self.tileName)
+ for j in xrange(-1, int(image.size[1] / tile.size[1]) + 1):
+ for i in xrange(-1, int(image.size[0] / tile.size[0]) + 1):
+ dest = (int((self.offset[0] + i) * tile.size[0]),
+ int((self.offset[1] + j) * tile.size[1]))
+ image.paste(tile, dest)
+
+
+class CroppedImage(Layer):
+ """Pick a random image, cropped randomly. Source images should be larger than the CAPTCHA."""
+ def __init__(self, imageFactory=Pictures.nature):
+ self.imageName = imageFactory.pick()
+ self.align = (random.uniform(0,1),
+ random.uniform(0,1))
+
+ def render(self, image):
+ i = Image.open(self.imageName)
+ image.paste(i, (int(self.align[0] * (image.size[0] - i.size[0])),
+ int(self.align[1] * (image.size[1] - i.size[1]))))
+
+
+class RandomDots(Layer):
+ """Draw random colored dots"""
+ def __init__(self, colors=("white", "black"), dotSize=4, numDots=400):
+ self.colors = colors
+ self.dotSize = dotSize
+ self.numDots = numDots
+ self.seed = random.random()
+
+ def render(self, image):
+ r = random.Random(self.seed)
+ for i in xrange(self.numDots):
+ bx = int(r.uniform(0, image.size[0]-self.dotSize))
+ by = int(r.uniform(0, image.size[1]-self.dotSize))
+ image.paste(r.choice(self.colors), (bx, by,
+ bx+self.dotSize-1,
+ by+self.dotSize-1))
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Backgrounds.pyc
Binary file pycaptcha/Captcha/Visual/Backgrounds.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Base.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Base.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,70 @@
+""" Captcha.Visual.BAse
+
+Base classes for visual CAPTCHAs. We use the Python Imaging Library
+to manipulate these images.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import Captcha
+import Image
+
+__all__ = ['ImageCaptcha', 'Layer']
+
+
+class ImageCaptcha(Captcha.BaseCaptcha):
+ """Base class for image-based CAPTCHA tests.
+ The render() function generates the CAPTCHA image at the given size by
+ combining Layer instances from self.layers, which should be created by
+ the subclass-defined getLayers().
+ """
+ defaultSize = (32,32)
+ # anciennement a defaultSize(256,96)
+ def __init__(self, *args, **kwargs):
+ Captcha.BaseCaptcha.__init__(self)
+ self._layers = self.getLayers(*args, **kwargs)
+
+ def getImage(self):
+ """Get a PIL image representing this CAPTCHA test, creating it if necessary"""
+ if not self._image:
+ self._image = self.render()
+ return self._image
+
+ def getLayers(self):
+ """Subclasses must override this to return a list of Layer instances to render.
+ Lists within the list of layers are recursively rendered.
+ """
+ return []
+
+ def render(self, size=None):
+ """Render this CAPTCHA, returning a PIL image"""
+ if size is None:
+ size = self.defaultSize
+ img = Image.new("L", size)
+ # img = Image.new("RGB", size)
+ return self._renderList(self._layers, Image.new("L", size))
+
+ def _renderList(self, l, img):
+ for i in l:
+ if type(i) == tuple or type(i) == list:
+ img = self._renderList(i, img)
+ else:
+ img = i.render(img) or img
+ return img
+
+
+class Layer(object):
+ """A renderable object representing part of a CAPTCHA.
+ The render() function should return approximately the same result, regardless
+ of the image size. This means any randomization must occur in the constructor.
+
+ If the render() function returns something non-None, it is taken as an image to
+ replace the current image with. This can be used to implement transformations
+ that result in a separate image without having to copy the results back to the first.
+ """
+ def render(self, img):
+ pass
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Base.pyc
Binary file pycaptcha/Captcha/Visual/Base.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Base.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Base.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,69 @@
+""" Captcha.Visual.BAse
+
+Base classes for visual CAPTCHAs. We use the Python Imaging Library
+to manipulate these images.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import Captcha
+import Image
+
+__all__ = ['ImageCaptcha', 'Layer']
+
+
+class ImageCaptcha(Captcha.BaseCaptcha):
+ """Base class for image-based CAPTCHA tests.
+ The render() function generates the CAPTCHA image at the given size by
+ combining Layer instances from self.layers, which should be created by
+ the subclass-defined getLayers().
+ """
+ defaultSize = (256,96)
+
+ def __init__(self, *args, **kwargs):
+ Captcha.BaseCaptcha.__init__(self)
+ self._layers = self.getLayers(*args, **kwargs)
+
+ def getImage(self):
+ """Get a PIL image representing this CAPTCHA test, creating it if necessary"""
+ if not self._image:
+ self._image = self.render()
+ return self._image
+
+ def getLayers(self):
+ """Subclasses must override this to return a list of Layer instances to render.
+ Lists within the list of layers are recursively rendered.
+ """
+ return []
+
+ def render(self, size=None):
+ """Render this CAPTCHA, returning a PIL image"""
+ if size is None:
+ size = self.defaultSize
+ img = Image.new("RGB", size)
+ return self._renderList(self._layers, Image.new("RGB", size))
+
+ def _renderList(self, l, img):
+ for i in l:
+ if type(i) == tuple or type(i) == list:
+ img = self._renderList(i, img)
+ else:
+ img = i.render(img) or img
+ return img
+
+
+class Layer(object):
+ """A renderable object representing part of a CAPTCHA.
+ The render() function should return approximately the same result, regardless
+ of the image size. This means any randomization must occur in the constructor.
+
+ If the render() function returns something non-None, it is taken as an image to
+ replace the current image with. This can be used to implement transformations
+ that result in a separate image without having to copy the results back to the first.
+ """
+ def render(self, img):
+ pass
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Distortions.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Distortions.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,117 @@
+""" Captcha.Visual.Distortions
+
+Distortion layers for visual CAPTCHAs
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha.Visual import Layer
+import ImageDraw, Image
+import random, math
+
+
+class WigglyBlocks(Layer):
+ """Randomly select and shift blocks of the image"""
+ def __init__(self, blockSize=3, sigma=0.01, iterations=300):
+ self.blockSize = blockSize
+ self.sigma = sigma
+ self.iterations = iterations
+ self.seed = random.random()
+
+ def render(self, image):
+ r = random.Random(self.seed)
+ for i in xrange(self.iterations):
+ # Select a block
+ bx = int(r.uniform(0, image.size[0]-self.blockSize))
+ by = int(r.uniform(0, image.size[1]-self.blockSize))
+ block = image.crop((bx, by, bx+self.blockSize-1, by+self.blockSize-1))
+
+ # Figure out how much to move it.
+ # The call to floor() is important so we always round toward
+ # 0 rather than to -inf. Just int() would bias the block motion.
+ mx = int(math.floor(r.normalvariate(0, self.sigma)))
+ my = int(math.floor(r.normalvariate(0, self.sigma)))
+
+ # Now actually move the block
+ image.paste(block, (bx+mx, by+my))
+
+
+class WarpBase(Layer):
+ """Abstract base class for image warping. Subclasses define a
+ function that maps points in the output image to points in the input image.
+ This warping engine runs a grid of points through this transform and uses
+ PIL's mesh transform to warp the image.
+ """
+ filtering = Image.BILINEAR
+ resolution = 10
+
+ def getTransform(self, image):
+ """Return a transformation function, subclasses should override this"""
+ return lambda x, y: (x, y)
+
+ def render(self, image):
+ r = self.resolution
+ xPoints = image.size[0] / r + 2
+ yPoints = image.size[1] / r + 2
+ f = self.getTransform(image)
+
+ # Create a list of arrays with transformed points
+ xRows = []
+ yRows = []
+ for j in xrange(yPoints):
+ xRow = []
+ yRow = []
+ for i in xrange(xPoints):
+ x, y = f(i*r, j*r)
+
+ # Clamp the edges so we don't get black undefined areas
+ x = max(0, min(image.size[0]-1, x))
+ y = max(0, min(image.size[1]-1, y))
+
+ xRow.append(x)
+ yRow.append(y)
+ xRows.append(xRow)
+ yRows.append(yRow)
+
+ # Create the mesh list, with a transformation for
+ # each square between points on the grid
+ mesh = []
+ for j in xrange(yPoints-1):
+ for i in xrange(xPoints-1):
+ mesh.append((
+ # Destination rectangle
+ (i*r, j*r,
+ (i+1)*r, (j+1)*r),
+ # Source quadrilateral
+ (xRows[j ][i ], yRows[j ][i ],
+ xRows[j+1][i ], yRows[j+1][i ],
+ xRows[j+1][i+1], yRows[j+1][i+1],
+ xRows[j ][i+1], yRows[j ][i+1]),
+ ))
+
+ return image.transform(image.size, Image.MESH, mesh, self.filtering)
+
+
+class SineWarp(WarpBase):
+ """Warp the image using a random composition of sine waves"""
+
+ def __init__(self,
+ amplitudeRange = (3, 6.5),
+ periodRange = (0.04, 0.1),
+ ):
+ self.amplitude = random.uniform(*amplitudeRange)
+ self.period = random.uniform(*periodRange)
+ self.offset = (random.uniform(0, math.pi * 2 / self.period),
+ random.uniform(0, math.pi * 2 / self.period))
+
+ def getTransform(self, image):
+ return (lambda x, y,
+ a = self.amplitude,
+ p = self.period,
+ o = self.offset:
+ (math.sin( (y+o[0])*p )*a + x,
+ math.sin( (x+o[1])*p )*a + y))
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Distortions.pyc
Binary file pycaptcha/Captcha/Visual/Distortions.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Distortions.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Distortions.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,117 @@
+""" Captcha.Visual.Distortions
+
+Distortion layers for visual CAPTCHAs
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha.Visual import Layer
+import ImageDraw, Image
+import random, math
+
+
+class WigglyBlocks(Layer):
+ """Randomly select and shift blocks of the image"""
+ def __init__(self, blockSize=3, sigma=0.01, iterations=300):
+ self.blockSize = blockSize
+ self.sigma = sigma
+ self.iterations = iterations
+ self.seed = random.random()
+
+ def render(self, image):
+ r = random.Random(self.seed)
+ for i in xrange(self.iterations):
+ # Select a block
+ bx = int(r.uniform(0, image.size[0]-self.blockSize))
+ by = int(r.uniform(0, image.size[1]-self.blockSize))
+ block = image.crop((bx, by, bx+self.blockSize-1, by+self.blockSize-1))
+
+ # Figure out how much to move it.
+ # The call to floor() is important so we always round toward
+ # 0 rather than to -inf. Just int() would bias the block motion.
+ mx = int(math.floor(r.normalvariate(0, self.sigma)))
+ my = int(math.floor(r.normalvariate(0, self.sigma)))
+
+ # Now actually move the block
+ image.paste(block, (bx+mx, by+my))
+
+
+class WarpBase(Layer):
+ """Abstract base class for image warping. Subclasses define a
+ function that maps points in the output image to points in the input image.
+ This warping engine runs a grid of points through this transform and uses
+ PIL's mesh transform to warp the image.
+ """
+ filtering = Image.BILINEAR
+ resolution = 10
+
+ def getTransform(self, image):
+ """Return a transformation function, subclasses should override this"""
+ return lambda x, y: (x, y)
+
+ def render(self, image):
+ r = self.resolution
+ xPoints = image.size[0] / r + 2
+ yPoints = image.size[1] / r + 2
+ f = self.getTransform(image)
+
+ # Create a list of arrays with transformed points
+ xRows = []
+ yRows = []
+ for j in xrange(yPoints):
+ xRow = []
+ yRow = []
+ for i in xrange(xPoints):
+ x, y = f(i*r, j*r)
+
+ # Clamp the edges so we don't get black undefined areas
+ x = max(0, min(image.size[0]-1, x))
+ y = max(0, min(image.size[1]-1, y))
+
+ xRow.append(x)
+ yRow.append(y)
+ xRows.append(xRow)
+ yRows.append(yRow)
+
+ # Create the mesh list, with a transformation for
+ # each square between points on the grid
+ mesh = []
+ for j in xrange(yPoints-1):
+ for i in xrange(xPoints-1):
+ mesh.append((
+ # Destination rectangle
+ (i*r, j*r,
+ (i+1)*r, (j+1)*r),
+ # Source quadrilateral
+ (xRows[j ][i ], yRows[j ][i ],
+ xRows[j+1][i ], yRows[j+1][i ],
+ xRows[j+1][i+1], yRows[j+1][i+1],
+ xRows[j ][i+1], yRows[j ][i+1]),
+ ))
+
+ return image.transform(image.size, Image.MESH, mesh, self.filtering)
+
+
+class SineWarp(WarpBase):
+ """Warp the image using a random composition of sine waves"""
+
+ def __init__(self,
+ amplitudeRange = (3, 6.5),
+ periodRange = (0.04, 0.1),
+ ):
+ self.amplitude = random.uniform(*amplitudeRange)
+ self.period = random.uniform(*periodRange)
+ self.offset = (random.uniform(0, math.pi * 2 / self.period),
+ random.uniform(0, math.pi * 2 / self.period))
+
+ def getTransform(self, image):
+ return (lambda x, y,
+ a = self.amplitude,
+ p = self.period,
+ o = self.offset:
+ (math.sin( (y+o[0])*p )*a + x,
+ math.sin( (x+o[1])*p )*a + y))
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Pictures.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Pictures.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,23 @@
+""" Captcha.Visual.Pictures
+
+Random collections of images
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha import File
+import Image
+
+
+class ImageFactory(File.RandomFileFactory):
+ """A factory that generates random images from a list"""
+ extensions = [".png", ".jpeg"]
+ basePath = "pictures"
+
+
+abstract = ImageFactory("abstract")
+nature = ImageFactory("nature")
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Pictures.pyc
Binary file pycaptcha/Captcha/Visual/Pictures.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Tests.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Tests.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,65 @@
+""" Captcha.Visual.Tests
+
+Visual CAPTCHA tests
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha.Visual import Text, Backgrounds, Distortions, ImageCaptcha
+from Captcha import Words
+import random
+
+__all__ = ["PseudoGimpy", "AngryGimpy", "AntiSpam"]
+
+
+class PseudoGimpy(ImageCaptcha):
+ """A relatively easy CAPTCHA that's somewhat easy on the eyes"""
+ def getLayers(self):
+ word = Words.defaultWordList.pick()
+ self.addSolution(word)
+ return [
+ # random.choice([
+ # Backgrounds.CroppedImage(),
+ # Backgrounds.TiledImage(),
+ # ]),
+ Text.TextLayer(word, borderSize=1),
+ Distortions.SineWarp(),
+ ]
+
+
+class AngryGimpy(ImageCaptcha):
+ """A harder but less visually pleasing CAPTCHA"""
+ def getLayers(self):
+ word = Words.defaultWordList.pick()
+ self.addSolution(word)
+ return [
+ # suppression du background
+ # Backgrounds.TiledImage(),
+ # Backgrounds.RandomDots(),
+ Text.TextLayer(word, borderSize=1),
+ # Distortions.SineWarp(periodRange = (0.04, 0.07))
+ Distortions.WigglyBlocks(),
+ ]
+
+
+class AntiSpam(ImageCaptcha):
+ """A fixed-solution CAPTCHA that can be used to hide email addresses or URLs from bots"""
+ fontFactory = Text.FontFactory(20, "vera/VeraBd.ttf")
+ defaultSize = (512,50)
+
+ def getLayers(self, solution="murray@example.com"):
+ self.addSolution(solution)
+
+ textLayer = Text.TextLayer(solution,
+ borderSize = 2,
+ fontFactory = self.fontFactory)
+
+ return [
+ Backgrounds.CroppedImage(),
+ textLayer,
+ Distortions.SineWarp(amplitudeRange = (3, 5)),
+ ]
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Tests.pyc
Binary file pycaptcha/Captcha/Visual/Tests.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Tests.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Tests.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,65 @@
+""" Captcha.Visual.Tests
+
+Visual CAPTCHA tests
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+from Captcha.Visual import Text, Backgrounds, Distortions, ImageCaptcha
+from Captcha import Words
+import random
+
+__all__ = ["PseudoGimpy", "AngryGimpy", "AntiSpam"]
+
+
+class PseudoGimpy(ImageCaptcha):
+ """A relatively easy CAPTCHA that's somewhat easy on the eyes"""
+ def getLayers(self):
+ word = Words.defaultWordList.pick()
+ self.addSolution(word)
+ return [
+ # random.choice([
+ # Backgrounds.CroppedImage(),
+ # Backgrounds.TiledImage(),
+ # ]),
+ Text.TextLayer(word, borderSize=1),
+ Distortions.SineWarp(),
+ ]
+
+
+class AngryGimpy(ImageCaptcha):
+ """A harder but less visually pleasing CAPTCHA"""
+ def getLayers(self):
+ word = Words.defaultWordList.pick()
+ self.addSolution(word)
+ return [
+ # suppression du background
+ # Backgrounds.TiledImage(),
+ # Backgrounds.RandomDots(),
+ Text.TextLayer(word, borderSize=1),
+ Distortions.SineWarp(periodRange = (0.04, 0.07))
+ # Distortions.WigglyBlocks(),
+ ]
+
+
+class AntiSpam(ImageCaptcha):
+ """A fixed-solution CAPTCHA that can be used to hide email addresses or URLs from bots"""
+ fontFactory = Text.FontFactory(20, "vera/VeraBd.ttf")
+ defaultSize = (512,50)
+
+ def getLayers(self, solution="murray@example.com"):
+ self.addSolution(solution)
+
+ textLayer = Text.TextLayer(solution,
+ borderSize = 2,
+ fontFactory = self.fontFactory)
+
+ return [
+ Backgrounds.CroppedImage(),
+ textLayer,
+ Distortions.SineWarp(amplitudeRange = (3, 5)),
+ ]
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Text.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Text.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,101 @@
+""" Captcha.Visual.Text
+
+Text generation for visual CAPTCHAs.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import random, os
+from Captcha import Visual, File
+import ImageFont, ImageDraw
+
+
+class FontFactory(File.RandomFileFactory):
+ """Picks random fonts and/or sizes from a given list.
+ 'sizes' can be a single size or a (min,max) tuple.
+ If any of the given files are directories, all *.ttf found
+ in that directory will be added.
+ """
+ extensions = [".ttf"]
+ basePath = "fonts"
+
+# arguments variables a modifier pour mettre le chemin vers les fontes.
+ def __init__(self, sizes, *fileNames):
+ File.RandomFileFactory.__init__(self, *fileNames)
+
+ if type(sizes) is tuple:
+ self.minSize = sizes[0]
+ self.maxSize = sizes[1]
+ else:
+ self.minSize = sizes
+ self.maxSize = sizes
+
+ def pick(self):
+ """Returns a (fileName, size) tuple that can be passed to ImageFont.truetype()"""
+ fileName = File.RandomFileFactory.pick(self)
+ size = int(random.uniform(self.minSize, self.maxSize) + 0.5)
+ return (fileName, size)
+
+# Predefined font factories
+defaultFontFactory = FontFactory(25, "vera", "others")
+#defaultFontFactory = FontFactory((30, 40), "vera")
+
+class TextLayer(Visual.Layer):
+ """Represents a piece of text rendered within the image.
+ Alignment is given such that (0,0) places the text in the
+ top-left corner and (1,1) places it in the bottom-left.
+
+ The font and alignment are optional, if not specified one is
+ chosen randomly. If no font factory is specified, the default is used.
+ """
+ def __init__(self, text,
+ alignment = None,
+ font = None,
+ fontFactory = None,
+ textColor = "white",
+ borderSize = 0,
+ borderColor = None,
+ ):
+ if fontFactory is None:
+ global defaultFontFactory
+ fontFactory = defaultFontFactory
+
+ if font is None:
+ font = fontFactory.pick()
+
+ if alignment is None:
+ alignment = (random.uniform(0,1),
+ random.uniform(0,1))
+
+ self.text = text
+ self.alignment = alignment
+ self.font = font
+ self.textColor = textColor
+ self.borderSize = borderSize
+ self.borderColor = borderColor
+
+ def render(self, img):
+ font = ImageFont.truetype(*self.font)
+ textSize = font.getsize(self.text)
+ draw = ImageDraw.Draw(img)
+
+ # Find the text's origin given our alignment and current image size
+ x = int((img.size[0] - textSize[0] - self.borderSize*2) * self.alignment[0] + 0.5)
+ y = int((img.size[1] - textSize[1] - self.borderSize*2) * self.alignment[1] + 0.5)
+
+ # Draw the border if we need one. This is slow and ugly, but there doesn't
+ # seem to be a better way with PIL.
+ if self.borderSize > 0:
+ for bx in (-1,0,1):
+ for by in (-1,0,1):
+ if bx and by:
+ draw.text((x + bx * self.borderSize,
+ y + by * self.borderSize),
+ self.text, font=font, fill=self.borderColor)
+
+ # And the text itself...
+ draw.text((x,y), self.text, font=font, fill=self.textColor)
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Text.pyc
Binary file pycaptcha/Captcha/Visual/Text.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/Text.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/Text.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,101 @@
+""" Captcha.Visual.Text
+
+Text generation for visual CAPTCHAs.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import random, os
+from Captcha import Visual, File
+import ImageFont, ImageDraw
+
+
+class FontFactory(File.RandomFileFactory):
+ """Picks random fonts and/or sizes from a given list.
+ 'sizes' can be a single size or a (min,max) tuple.
+ If any of the given files are directories, all *.ttf found
+ in that directory will be added.
+ """
+ extensions = [".ttf", ".bdf"]
+ basePath = "fonts"
+
+# arguments variables a modifier pour mettre le chemin vers les fontes.
+ def __init__(self, sizes, *fileNames):
+ File.RandomFileFactory.__init__(self, *fileNames)
+
+ if type(sizes) is tuple:
+ self.minSize = sizes[0]
+ self.maxSize = sizes[1]
+ else:
+ self.minSize = sizes
+ self.maxSize = sizes
+
+ def pick(self):
+ """Returns a (fileName, size) tuple that can be passed to ImageFont.truetype()"""
+ fileName = File.RandomFileFactory.pick(self)
+ size = int(random.uniform(self.minSize, self.maxSize) + 0.5)
+ return (fileName, size)
+
+# Predefined font factories
+defaultFontFactory = FontFactory(25, "vera", "mlm", "others")
+#defaultFontFactory = FontFactory((30, 40), "vera")
+
+class TextLayer(Visual.Layer):
+ """Represents a piece of text rendered within the image.
+ Alignment is given such that (0,0) places the text in the
+ top-left corner and (1,1) places it in the bottom-left.
+
+ The font and alignment are optional, if not specified one is
+ chosen randomly. If no font factory is specified, the default is used.
+ """
+ def __init__(self, text,
+ alignment = None,
+ font = None,
+ fontFactory = None,
+ textColor = "white",
+ borderSize = 0,
+ borderColor = None,
+ ):
+ if fontFactory is None:
+ global defaultFontFactory
+ fontFactory = defaultFontFactory
+
+ if font is None:
+ font = fontFactory.pick()
+
+ if alignment is None:
+ alignment = (random.uniform(0,1),
+ random.uniform(0,1))
+
+ self.text = text
+ self.alignment = alignment
+ self.font = font
+ self.textColor = textColor
+ self.borderSize = borderSize
+ self.borderColor = borderColor
+
+ def render(self, img):
+ font = ImageFont.truetype(*self.font)
+ textSize = font.getsize(self.text)
+ draw = ImageDraw.Draw(img)
+
+ # Find the text's origin given our alignment and current image size
+ x = int((img.size[0] - textSize[0] - self.borderSize*2) * self.alignment[0] + 0.5)
+ y = int((img.size[1] - textSize[1] - self.borderSize*2) * self.alignment[1] + 0.5)
+
+ # Draw the border if we need one. This is slow and ugly, but there doesn't
+ # seem to be a better way with PIL.
+ if self.borderSize > 0:
+ for bx in (-1,0,1):
+ for by in (-1,0,1):
+ if bx and by:
+ draw.text((x + bx * self.borderSize,
+ y + by * self.borderSize),
+ self.text, font=font, fill=self.borderColor)
+
+ # And the text itself...
+ draw.text((x,y), self.text, font=font, fill=self.textColor)
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Visual/__init__.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,14 @@
+""" Captcha.Visual
+
+This package contains functionality specific to visual CAPTCHA tests.
+
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+# Convenience imports
+from Base import *
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Visual/__init__.pyc
Binary file pycaptcha/Captcha/Visual/__init__.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Words.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Words.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,58 @@
+""" Captcha.Words
+
+Utilities for managing word lists and finding random words
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import random, os
+import File
+
+
+class WordList(object):
+ """A class representing a word list read from disk lazily.
+ Blank lines and comment lines starting with '#' are ignored.
+ Any number of words per line may be used. The list can
+ optionally ingore words not within a given length range.
+ """
+ def __init__(self, fileName, minLength=None, maxLength=None):
+ self.words = None
+ self.fileName = fileName
+ self.minLength = minLength
+ self.maxLength = maxLength
+
+ def read(self):
+ """Read words from disk"""
+ f = open(os.path.join(File.dataDir, "words", self.fileName))
+
+ self.words = []
+ for line in f.xreadlines():
+ line = line.strip()
+ if not line:
+ continue
+ if line[0] == '#':
+ continue
+ for word in line.split():
+ if self.minLength is not None and len(word) < self.minLength:
+ continue
+ if self.maxLength is not None and len(word) > self.maxLength:
+ continue
+ self.words.append(word)
+
+ def pick(self):
+ """Pick a random word from the list, reading it in if necessary"""
+ if self.words is None:
+ self.read()
+ return random.choice(self.words)
+
+
+# Define several shared word lists that are read from disk on demand
+basic_english = WordList("basic-english")
+basic_english_restricted = WordList("basic-english", minLength=5, maxLength=8)
+characters = WordList("characters")
+defaultWordList = characters
+
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Words.pyc
Binary file pycaptcha/Captcha/Words.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/Words.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/Words.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,57 @@
+""" Captcha.Words
+
+Utilities for managing word lists and finding random words
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+import random, os
+import File
+
+
+class WordList(object):
+ """A class representing a word list read from disk lazily.
+ Blank lines and comment lines starting with '#' are ignored.
+ Any number of words per line may be used. The list can
+ optionally ingore words not within a given length range.
+ """
+ def __init__(self, fileName, minLength=None, maxLength=None):
+ self.words = None
+ self.fileName = fileName
+ self.minLength = minLength
+ self.maxLength = maxLength
+
+ def read(self):
+ """Read words from disk"""
+ f = open(os.path.join(File.dataDir, "words", self.fileName))
+
+ self.words = []
+ for line in f.xreadlines():
+ line = line.strip()
+ if not line:
+ continue
+ if line[0] == '#':
+ continue
+ for word in line.split():
+ if self.minLength is not None and len(word) < self.minLength:
+ continue
+ if self.maxLength is not None and len(word) > self.maxLength:
+ continue
+ self.words.append(word)
+
+ def pick(self):
+ """Pick a random word from the list, reading it in if necessary"""
+ if self.words is None:
+ self.read()
+ return random.choice(self.words)
+
+
+# Define several shared word lists that are read from disk on demand
+basic_english = WordList("basic-english")
+basic_english_restricted = WordList("basic-english", minLength=5, maxLength=8)
+
+defaultWordList = basic_english_restricted
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/__init__.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,41 @@
+""" Captcha
+
+This is the PyCAPTCHA package, a collection of Python modules
+implementing CAPTCHAs: automated tests that humans should pass,
+but current computer programs can't. These tests are often
+used for security.
+
+See http://www.captcha.net for more information and examples.
+
+This project was started because the CIA project, written in
+Python, needed a CAPTCHA to automate its user creation process
+safely. All existing implementations the author could find were
+written in Java or for the .NET framework, so a simple Python
+alternative was needed.
+"""
+#
+# PyCAPTCHA Package
+# Copyright (C) 2004 Micah Dowty
+#
+
+__version__ = "0.3-pre"
+
+
+# Check the python version here before we proceed further
+requiredPythonVersion = (2,2,1)
+def checkVersion():
+ import sys, string
+ if sys.version_info < requiredPythonVersion:
+ raise Exception("%s requires at least Python %s, found %s instead." % (
+ name,
+ string.join(map(str, requiredPythonVersion), "."),
+ string.join(map(str, sys.version_info), ".")))
+checkVersion()
+
+
+# Convenience imports
+from Base import *
+import File
+import Words
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/__init__.pyc
Binary file pycaptcha/Captcha/__init__.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/.DS_Store
Binary file pycaptcha/Captcha/data/.DS_Store has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/.DS_Store
Binary file pycaptcha/Captcha/data/fonts/.DS_Store has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/._atari-small.bdf
Binary file pycaptcha/Captcha/data/fonts/others/._atari-small.bdf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/._cursive.bdf
Binary file pycaptcha/Captcha/data/fonts/others/._cursive.bdf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/._radon-wide.bdf
Binary file pycaptcha/Captcha/data/fonts/others/._radon-wide.bdf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/CIDFnmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/others/CIDFnmap Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,10 @@
+/Dotum-Bold (/usr/share/fonts/truetype/unfonts/UnDotumBold.ttf) /Adobe-Korea1-Unicode ;
+/ZenHei (/usr/share/fonts/truetype/wqy/wqy-zenhei.ttf) /Adobe-GB1-Unicode ;
+/Batang-Regular (/usr/share/fonts/truetype/unfonts/UnBatang.ttf) /Adobe-Korea1-Unicode ;
+/VL-PGothic-Regular (/usr/share/fonts/truetype/vlgothic/VL-PGothic-Regular.ttf) /Adobe-Japan1-Unicode ;
+/Dotum-Regular (/usr/share/fonts/truetype/unfonts/UnDotum.ttf) /Adobe-Korea1-Unicode ;
+/VL-Gothic-Regular-JaH (/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf) /Adobe-Japan2-Unicode ;
+/VL-Gothic-Regular (/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf) /Adobe-Japan1-Unicode ;
+/VL-PGothic-Regular-JaH (/usr/share/fonts/truetype/vlgothic/VL-PGothic-Regular.ttf) /Adobe-Japan2-Unicode ;
+/ZenHei-CNS (/usr/share/fonts/truetype/wqy/wqy-zenhei.ttf) /Adobe-CNS1-Unicode ;
+/Batang-Bold (/usr/share/fonts/truetype/unfonts/UnBatangBold.ttf) /Adobe-Korea1-Unicode ;
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/FAPIfontmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/others/FAPIfontmap Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,155 @@
+/Garuda-Oblique << /Path (/usr/share/fonts/truetype/thai/Garuda-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Sans << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstOne << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstOne.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Vemana2000 << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/Vemana.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSerif-Bold << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypo-Bold << /Path (/usr/share/fonts/truetype/thai/TlwgTypo-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSerif-BoldItalic << /Path (/usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush-Oblique << /Path (/usr/share/fonts/truetype/thai/Umpush-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationMono-Italic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Italic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Malige << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/Malige-b.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Loma-Oblique << /Path (/usr/share/fonts/truetype/thai/Loma-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstBook << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstBook.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi-BoldItalic << /Path (/usr/share/fonts/truetype/thai/Norasi-BoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Sans-Bold << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Norasi-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeMono-BoldOblique << /Path (/usr/share/fonts/truetype/freefont/FreeMonoBoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Serif << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstOffice << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstOffice.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypist-Oblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypist-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSans-Italic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Italic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Waree-Oblique << /Path (/usr/share/fonts/truetype/thai/Waree-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationMono-BoldItalic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationMono-BoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstFarsi << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstFarsi.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgMono-Oblique << /Path (/usr/share/fonts/truetype/thai/TlwgMono-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Garuda-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Garuda-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSans-BoldOblique << /Path (/usr/share/fonts/truetype/freefont/FreeSansBoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/utkal << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/utkal.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSerif-Italic << /Path (/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypist-Bold << /Path (/usr/share/fonts/truetype/thai/TlwgTypist-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSerif-Italic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Italic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Sawasdee-BoldOblique << /Path (/usr/share/fonts/truetype/thai/SawasdeeBoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Umpush-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/cmex10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/cmex10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeMono-Bold << /Path (/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi-Bold << /Path (/usr/share/fonts/truetype/thai/Norasi-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSans-Regular << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Regular.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Loma << /Path (/usr/share/fonts/truetype/thai/Loma.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/wasy10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/wasy10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari-BoldItalic << /Path (/usr/share/fonts/truetype/thai/Kinnari-BoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstNaskh << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstNaskh.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSans-Bold << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Waree << /Path (/usr/share/fonts/truetype/thai/Waree.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Garuda << /Path (/usr/share/fonts/truetype/thai/Garuda.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/cmsy10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/cmsy10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypist-BoldOblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypist-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Sawasdee-Bold << /Path (/usr/share/fonts/truetype/thai/SawasdeeBold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Purisa << /Path (/usr/share/fonts/truetype/thai/Purisa.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstPoster << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstPoster.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSans-Oblique << /Path (/usr/share/fonts/truetype/freefont/FreeSansOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypo-BoldOblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypo-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Lohit-Punjabi << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Waree-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Waree-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypewriter-BoldOblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypewriter-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Garuda-Bold << /Path (/usr/share/fonts/truetype/thai/Garuda-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/RachanaMedium << /Path (/usr/share/fonts/truetype/ttf-malayalam-fonts/Rachana_04.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstArt << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstArt.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationMono-Bold << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypo-Oblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypo-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSerif-Bold << /Path (/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSerif-BoldItalic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-BoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstDecorative << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstDecorative.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Lohit-Hindi << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_hi.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush-LightOblique << /Path (/usr/share/fonts/truetype/thai/Umpush-LightOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSerif-Medium << /Path (/usr/share/fonts/truetype/freefont/FreeSerif.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/mry_KacstQurn << /Path (/usr/share/fonts/truetype/ttf-kacst/mry_KacstQurn.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstDigital << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstDigital.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Sans-Mono-Bold << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Lohit-Gujarati << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_gu.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationMono-Regular << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Regular.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstLetter << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstLetter.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypo << /Path (/usr/share/fonts/truetype/thai/TlwgTypo.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/msbm10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/msbm10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgMono-Bold << /Path (/usr/share/fonts/truetype/thai/TlwgMono-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Sans-Mono << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi-Italic << /Path (/usr/share/fonts/truetype/thai/Norasi-Italic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstTitleL << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstTitleL.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypewriter << /Path (/usr/share/fonts/truetype/thai/TlwgTypewriter.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeMono-Medium << /Path (/usr/share/fonts/truetype/freefont/FreeMono.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi-Oblique << /Path (/usr/share/fonts/truetype/thai/Norasi-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypewriter-Oblique << /Path (/usr/share/fonts/truetype/thai/TlwgTypewriter-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Phetsarath << /Path (/usr/share/fonts/truetype/ttf-lao/Phetsarath_OT.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/mukti << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/MuktiNarrow.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Sawasdee-Oblique << /Path (/usr/share/fonts/truetype/thai/SawasdeeOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/cmr10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/cmr10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush-Light << /Path (/usr/share/fonts/truetype/thai/Umpush-Light.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush-Bold << /Path (/usr/share/fonts/truetype/thai/Umpush-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/DejaVu-Serif-Bold << /Path (/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstTitle << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstTitle.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Norasi << /Path (/usr/share/fonts/truetype/thai/Norasi.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari-Oblique << /Path (/usr/share/fonts/truetype/thai/Kinnari-Oblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/muktinarrow << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/MuktiNarrowBold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari-Italic << /Path (/usr/share/fonts/truetype/thai/Kinnari-Italic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/kacstPen << /Path (/usr/share/fonts/truetype/ttf-kacst/kacstPen.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Kinnari-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypewriter-Bold << /Path (/usr/share/fonts/truetype/thai/TlwgTypewriter-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeMono-Oblique << /Path (/usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSans-Medium << /Path (/usr/share/fonts/truetype/freefont/FreeSans.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSerif-Regular << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Regular.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Umpush << /Path (/usr/share/fonts/truetype/thai/Umpush.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Sawasdee << /Path (/usr/share/fonts/truetype/thai/Sawasdee.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgMono << /Path (/usr/share/fonts/truetype/thai/TlwgMono.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstQurn << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstQurn.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari << /Path (/usr/share/fonts/truetype/thai/Kinnari.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgMono-BoldOblique << /Path (/usr/share/fonts/truetype/thai/TlwgMono-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/KacstScreen << /Path (/usr/share/fonts/truetype/ttf-kacst/KacstScreen.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/FreeSans-Bold << /Path (/usr/share/fonts/truetype/freefont/FreeSansBold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/msam10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/msam10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/cmmi10 << /Path (/usr/share/fonts/truetype/latex-xft-fonts/cmmi10.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Lohit-Tamil << /Path (/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_ta.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/TlwgTypist << /Path (/usr/share/fonts/truetype/thai/TlwgTypist.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Waree-Bold << /Path (/usr/share/fonts/truetype/thai/Waree-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Kinnari-Bold << /Path (/usr/share/fonts/truetype/thai/Kinnari-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Loma-Bold << /Path (/usr/share/fonts/truetype/thai/Loma-Bold.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/LiberationSans-BoldItalic << /Path (/usr/share/fonts/truetype/ttf-liberation/LiberationSans-BoldItalic.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Loma-BoldOblique << /Path (/usr/share/fonts/truetype/thai/Loma-BoldOblique.ttf) /FontType 1 /FAPI /FreeType /SubfontId 0 >> ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/HelveticaNarrow-BoldOblique /NimbusSanL-BoldCondItal ;
+/Times-Roman /NimbusRomNo9L-Regu ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/HelveticaNarrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+/Traditional /KacstBook ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Courier /NimbusMonL-Regu ;
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/HelveticaNarrow-Oblique /NimbusSanL-ReguCondItal ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+/HelveticaNarrow-Bold /NimbusSanL-BoldCond ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+/ZapfDingbats /Dingbats ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+/Helvetica /NimbusSanL-Regu ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Palatino-Roman /URWPalladioL-Roma ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Arabic /KacstBook ;
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/Fontmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/others/Fontmap Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,116 @@
+/LMTypewriter10-CapsOblique (lmtcso10.pfb) ;
+/Dingbats (d050000l.pfb) ;
+/URWBookmanL-DemiBoldItal (b018035l.pfb) ;
+/LMSansQuotation8-Bold (lmssqbx8.pfb) ;
+/Symbol (Symbol.pfb) ;
+/LMTypewriterVarWd10-DarkOblique (lmvtko10.pfb) ;
+/LMRoman10-Demi (lmb10.pfb) ;
+/URWPalladioL-Ital (p052023l.pfb) ;
+/LMTypewriter10-DarkOblique (lmtko10.pfb) ;
+/NimbusSanL-Regu (n019003l.pfb) ;
+/LMTypewriter10-Italic (lmtti10.pfb) ;
+/LMSansQuotation8-BoldOblique (lmssqbo8.pfb) ;
+/URWPalladioL-Roma (p052003l.pfb) ;
+/LMTypewriterVarWd10-Light (lmvtl10.pfb) ;
+/NimbusRomNo9L-Medi (n021004l.pfb) ;
+/NimbusSanL-ReguItal (n019023l.pfb) ;
+/NimbusMonL-Regu (n022003l.pfb) ;
+/LMSans10-Bold (lmssbx10.pfb) ;
+/LMRoman10-CapsOblique (lmcsco10.pfb) ;
+/CenturySchL-Roma (c059013l.pfb) ;
+/URWGothicL-BookObli (a010033l.pfb) ;
+/LMTypewriter10-LightCondensedOblique (lmtlco10.pfb) ;
+/LMSans10-DemiCondensedOblique (lmssdo10.pfb) ;
+/LMRoman10-CapsRegular (lmcsc10.pfb) ;
+/CenturySchL-BoldItal (c059036l.pfb) ;
+/LMRoman10-DemiOblique (lmbo10.pfb) ;
+/LMRoman10-Unslanted (lmu10.pfb) ;
+/LMRoman10-Bold (lmbx10.pfb) ;
+/LMSans10-DemiCondensed (lmssdc10.pfb) ;
+/URWChanceryL-MediItal (z003034l.pfb) ;
+/URWGothicL-DemiObli (a010035l.pfb) ;
+/LMTypewriterVarWd10-Oblique (lmvtto10.pfb) ;
+/NimbusMonL-Bold (n022004l.pfb) ;
+/LMTypewriter10-Oblique (lmtto10.pfb) ;
+/LMRoman10-BoldItalic (lmbxi10.pfb) ;
+/NimbusSanL-ReguCond (n019043l.pfb) ;
+/CenturySchL-Bold (c059016l.pfb) ;
+/LMTypewriterVarWd10-Regular (lmvtt10.pfb) ;
+/URWBookmanL-Ligh (b018012l.pfb) ;
+/LMSansQuotation8-Regular (lmssq8.pfb) ;
+/LMSans10-Regular (lmss10.pfb) ;
+/LMSans10-Oblique (lmsso10.pfb) ;
+/NimbusSanL-BoldCond (n019044l.pfb) ;
+/LMRoman10-Regular (lmr10.pfb) ;
+/LMTypewriter10-LightCondensed (lmtlc10.pfb) ;
+/LMTypewriterVarWd10-Dark (lmvtk10.pfb) ;
+/LMTypewriter10-CapsRegular (lmtcsc10.pfb) ;
+/LMSansQuotation8-Oblique (lmssqo8.pfb) ;
+/StandardSymL (s050000l.pfb) ;
+/NimbusRomNo9L-Regu (n021003l.pfb) ;
+/LMTypewriterVarWd10-LightOblique (lmvtlo10.pfb) ;
+/URWPalladioL-BoldItal (p052024l.pfb) ;
+/CenturySchL-Ital (c059033l.pfb) ;
+/LMRoman10-Dunhill (lmdunh10.pfb) ;
+/URWPalladioL-Bold (p052004l.pfb) ;
+/URWGothicL-Book (a010013l.pfb) ;
+/LMTypewriter10-Dark (lmtk10.pfb) ;
+/NimbusSanL-BoldItal (n019024l.pfb) ;
+/URWGothicL-Demi (a010015l.pfb) ;
+/LMTypewriter10-LightOblique (lmtlo10.pfb) ;
+/LMTypewriter10-Light (lmtl10.pfb) ;
+/NimbusSanL-BoldCondItal (n019064l.pfb) ;
+/LMRoman10-Italic (lmri10.pfb) ;
+/LMRoman10-DunhillOblique (lmduno10.pfb) ;
+/NimbusMonL-ReguObli (n022023l.pfb) ;
+/LMRoman10-Oblique (lmro10.pfb) ;
+/NimbusSanL-ReguCondItal (n019063l.pfb) ;
+/NimbusRomNo9L-MediItal (n021024l.pfb) ;
+/LMRoman10-BoldOblique (lmbxo10.pfb) ;
+/URWBookmanL-DemiBold (b018015l.pfb) ;
+/NimbusSanL-Bold (n019004l.pfb) ;
+/LMSans10-BoldOblique (lmssbo10.pfb) ;
+/URWBookmanL-LighItal (b018032l.pfb) ;
+/NimbusMonL-BoldObli (n022024l.pfb) ;
+/NimbusRomNo9L-ReguItal (n021023l.pfb) ;
+/LMTypewriter10-Regular (lmtt10.pfb) ;
+/Palatino-Italic /URWPalladioL-Ital ;
+/Palatino-Bold /URWPalladioL-Bold ;
+/AvantGarde-BookOblique /URWGothicL-BookObli ;
+/Times-Bold /NimbusRomNo9L-Medi ;
+/HelveticaNarrow-BoldOblique /NimbusSanL-BoldCondItal ;
+/Times-Roman /NimbusRomNo9L-Regu ;
+/NewCenturySchlbk-Italic /CenturySchL-Ital ;
+/HelveticaNarrow /NimbusSanL-ReguCond ;
+/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ;
+/Bookman-Light /URWBookmanL-Ligh ;
+/Palatino-BoldItalic /URWPalladioL-BoldItal ;
+/Traditional /KacstBook ;
+/Times-BoldItalic /NimbusRomNo9L-MediItal ;
+/AvantGarde-Book /URWGothicL-Book ;
+/AvantGarde-DemiOblique /URWGothicL-DemiObli ;
+/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ;
+/Helvetica-Bold /NimbusSanL-Bold ;
+/Courier-Oblique /NimbusMonL-ReguObli ;
+/Times-Italic /NimbusRomNo9L-ReguItal ;
+/Courier /NimbusMonL-Regu ;
+/Bookman-Demi /URWBookmanL-DemiBold ;
+/Helvetica-BoldOblique /NimbusSanL-BoldItal ;
+/Helvetica-Oblique /NimbusSanL-ReguItal ;
+/HelveticaNarrow-Oblique /NimbusSanL-ReguCondItal ;
+/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ;
+/Courier-BoldOblique /NimbusMonL-BoldObli ;
+/HelveticaNarrow-Bold /NimbusSanL-BoldCond ;
+/AvantGarde-Demi /URWGothicL-Demi ;
+/Bookman-LightItalic /URWBookmanL-LighItal ;
+/ZapfDingbats /Dingbats ;
+/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ;
+/ZapfChancery-MediumItalic /URWChanceryL-MediItal ;
+/Helvetica /NimbusSanL-Regu ;
+/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ;
+/Palatino-Roman /URWPalladioL-Roma ;
+/NewCenturySchlbk-Bold /CenturySchL-Bold ;
+/NewCenturySchlbk-Roman /CenturySchL-Roma ;
+/Courier-Bold /NimbusMonL-Bold ;
+/Arabic /KacstBook ;
+/Helvetica-Narrow /NimbusSanL-ReguCond ;
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/others/cidfmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/others/cidfmap Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,10 @@
+/Dotum-Bold << /FileType /TrueType /Path (/usr/share/fonts/truetype/unfonts/UnDotumBold.ttf) /SubfontID 0 /CSI [(Korea1) 0] >> ;
+/ZenHei << /FileType /TrueType /Path (/usr/share/fonts/truetype/wqy/wqy-zenhei.ttf) /SubfontID 0 /CSI [(GB1) 0] >> ;
+/Batang-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/unfonts/UnBatang.ttf) /SubfontID 0 /CSI [(Korea1) 0] >> ;
+/VL-PGothic-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/vlgothic/VL-PGothic-Regular.ttf) /SubfontID 0 /CSI [(Japan1) 0] >> ;
+/Dotum-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/unfonts/UnDotum.ttf) /SubfontID 0 /CSI [(Korea1) 0] >> ;
+/VL-Gothic-Regular-JaH << /FileType /TrueType /Path (/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf) /SubfontID 0 /CSI [(Japan2) 0] >> ;
+/VL-Gothic-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf) /SubfontID 0 /CSI [(Japan1) 0] >> ;
+/VL-PGothic-Regular-JaH << /FileType /TrueType /Path (/usr/share/fonts/truetype/vlgothic/VL-PGothic-Regular.ttf) /SubfontID 0 /CSI [(Japan2) 0] >> ;
+/ZenHei-CNS << /FileType /TrueType /Path (/usr/share/fonts/truetype/wqy/wqy-zenhei.ttf) /SubfontID 0 /CSI [(CNS1) 0] >> ;
+/Batang-Bold << /FileType /TrueType /Path (/usr/share/fonts/truetype/unfonts/UnBatangBold.ttf) /SubfontID 0 /CSI [(Korea1) 0] >> ;
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/COPYRIGHT.TXT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/vera/COPYRIGHT.TXT Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,124 @@
+Bitstream Vera Fonts Copyright
+
+The fonts have a generous copyright, allowing derivative works (as
+long as "Bitstream" or "Vera" are not in the names), and full
+redistribution (so long as they are not *sold* by themselves). They
+can be be bundled, redistributed and sold with any software.
+
+The fonts are distributed under the following copyright:
+
+Copyright
+=========
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
+Vera is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute
+the Font Software, including without limitation the rights to use,
+copy, merge, publish, distribute, and/or sell copies of the Font
+Software, and to permit persons to whom the Font Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Bitstream" or the word "Vera".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Bitstream Vera" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
+OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
+SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font
+Software without prior written authorization from the Gnome Foundation
+or Bitstream Inc., respectively. For further information, contact:
+fonts at gnome dot org.
+
+Copyright FAQ
+=============
+
+ 1. I don't understand the resale restriction... What gives?
+
+ Bitstream is giving away these fonts, but wishes to ensure its
+ competitors can't just drop the fonts as is into a font sale system
+ and sell them as is. It seems fair that if Bitstream can't make money
+ from the Bitstream Vera fonts, their competitors should not be able to
+ do so either. You can sell the fonts as part of any software package,
+ however.
+
+ 2. I want to package these fonts separately for distribution and
+ sale as part of a larger software package or system. Can I do so?
+
+ Yes. A RPM or Debian package is a "larger software package" to begin
+ with, and you aren't selling them independently by themselves.
+ See 1. above.
+
+ 3. Are derivative works allowed?
+ Yes!
+
+ 4. Can I change or add to the font(s)?
+ Yes, but you must change the name(s) of the font(s).
+
+ 5. Under what terms are derivative works allowed?
+
+ You must change the name(s) of the fonts. This is to ensure the
+ quality of the fonts, both to protect Bitstream and Gnome. We want to
+ ensure that if an application has opened a font specifically of these
+ names, it gets what it expects (though of course, using fontconfig,
+ substitutions could still could have occurred during font
+ opening). You must include the Bitstream copyright. Additional
+ copyrights can be added, as per copyright law. Happy Font Hacking!
+
+ 6. If I have improvements for Bitstream Vera, is it possible they might get
+ adopted in future versions?
+
+ Yes. The contract between the Gnome Foundation and Bitstream has
+ provisions for working with Bitstream to ensure quality additions to
+ the Bitstream Vera font family. Please contact us if you have such
+ additions. Note, that in general, we will want such additions for the
+ entire family, not just a single font, and that you'll have to keep
+ both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
+ glyphs to the font, they must be stylistically in keeping with Vera's
+ design. Vera cannot become a "ransom note" font. Jim Lyles will be
+ providing a document describing the design elements used in Vera, as a
+ guide and aid for people interested in contributing to Vera.
+
+ 7. I want to sell a software package that uses these fonts: Can I do so?
+
+ Sure. Bundle the fonts with your software and sell your software
+ with the fonts. That is the intent of the copyright.
+
+ 8. If applications have built the names "Bitstream Vera" into them,
+ can I override this somehow to use fonts of my choosing?
+
+ This depends on exact details of the software. Most open source
+ systems and software (e.g., Gnome, KDE, etc.) are now converting to
+ use fontconfig (see www.fontconfig.org) to handle font configuration,
+ selection and substitution; it has provisions for overriding font
+ names and subsituting alternatives. An example is provided by the
+ supplied local.conf file, which chooses the family Bitstream Vera for
+ "sans", "serif" and "monospace". Other software (e.g., the XFree86
+ core server) has other mechanisms for font substitution.
+
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/README.TXT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/vera/README.TXT Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,11 @@
+Contained herin is the Bitstream Vera font family.
+
+The Copyright information is found in the COPYRIGHT.TXT file (along
+with being incoporated into the fonts themselves).
+
+The releases notes are found in the file "RELEASENOTES.TXT".
+
+We hope you enjoy Vera!
+
+ Bitstream, Inc.
+ The Gnome Project
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/RELEASENOTES.TXT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/vera/RELEASENOTES.TXT Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,162 @@
+Bitstream Vera Fonts - April 16, 2003
+=====================================
+
+The version number of these fonts is 1.10 to distinguish them from the
+beta test fonts.
+
+Note that the Vera copyright is incorporated in the fonts themselves.
+The License field in the fonts contains the copyright license as it
+appears below. The TrueType copyright field is not large enough to
+contain the full license, so the license is incorporated (as you might
+think if you thought about it) into the license field, which
+unfortunately can be obscure to find. (In pfaedit, see: Element->Font
+Info->TTFNames->License).
+
+Our apologies for it taking longer to complete the fonts than planned.
+Beta testers requested a tighter line spacing (less leading) and Jim
+Lyles redesigned Vera's accents to bring its line spacing to more
+typical of other fonts. This took additional time and effort. Our
+thanks to Jim for this effort above and beyond the call of duty.
+
+There are four monospace and sans faces (normal, oblique, bold, bold
+oblique) and two serif faces (normal and bold). Fontconfig/Xft2 (see
+www.fontconfig.org) can artificially oblique the serif faces for you:
+this loses hinting and distorts the faces slightly, but is visibly
+different than normal and bold, and reasonably pleasing.
+
+On systems with fontconfig 2.0 or 2.1 installed, making your sans,
+serif and monospace fonts default to these fonts is very easy. Just
+drop the file local.conf into your /etc/fonts directory. This will
+make the Bitstream fonts your default fonts for all applications using
+fontconfig (if sans, serif, or monospace names are used, as they often
+are as default values in many desktops). The XML in local.conf may
+need modification to enable subpixel decimation, if appropriate,
+however, the commented out phrase does so for XFree86 4.3, in the case
+that the server does not have sufficient information to identify the
+use of a flat panel. Fontconfig 2.2 adds Vera to the list of font
+families and will, by default use it as the default sans, serif and
+monospace fonts.
+
+During the testing of the final Vera fonts, we learned that screen
+fonts in general are only typically hinted to work correctly at
+integer pixel sizes. Vera is coded internally for integer sizes only.
+We need to investigate further to see if there are commonly used fonts
+that are hinted to be rounded but are not rounded to integer sizes due
+to oversights in their coding.
+
+Most fonts work best at 8 pixels and below if anti-aliased only, as
+the amount of work required to hint well at smaller and smaller sizes
+becomes astronomical. GASP tables are typically used to control
+whether hinting is used or not, but Freetype/Xft does not currently
+support GASP tables (which are present in Vera).
+
+To mitigate this problem, both for Vera and other fonts, there will be
+(very shortly) a new fontconfig 2.2 release that will, by default not
+apply hints if the size is below 8 pixels. if you should have a font
+that in fact has been hinted more agressively, you can use fontconfig
+to note this exception. We believe this should improve many hinted
+fonts in addition to Vera, though implemeting GASP support is likely
+the right long term solution.
+
+Font rendering in Gnome or KDE is the combination of algorithms in
+Xft2 and Freetype, along with hinting in the fonts themselves. It is
+vital to have sufficient information to disentangle problems that you
+may observe.
+
+Note that having your font rendering system set up correctly is vital
+to proper judgement of problems of the fonts:
+
+ * Freetype may or may not be configured to in ways that may
+ implement execution of possibly patented (in some parts of the world)
+ TrueType hinting algorithms, particularly at small sizes. Best
+ results are obtained while using these algorithms.
+
+ * The freetype autohinter (used when the possibly patented
+ algorithms are not used) continues to improve with each release. If
+ you are using the autohinter, please ensure you are using an up to
+ date version of freetype before reporting problems.
+
+ * Please identify what version of freetype you are using in any
+ bug reports, and how your freetype is configured.
+
+ * Make sure you are not using the freetype version included in
+ XFree86 4.3, as it has bugs that significantly degrade most fonts,
+ including Vera. if you build XFree86 4.3 from source yourself, you may
+ have installed this broken version without intending it (as I
+ did). Vera was verified with the recently released Freetype 2.1.4. On
+ many systems, 'ldd" can be used to see which freetype shared library
+ is actually being used.
+
+ * Xft/X Render does not (yet) implement gamma correction. This
+ causes significant problems rendering white text on a black background
+ (causing partial pixels to be insufficiently shaded) if the gamma of
+ your monitor has not been compensated for, and minor problems with
+ black text on a while background. The program "xgamma" can be used to
+ set a gamma correction value in the X server's color pallette. Most
+ monitors have a gamma near 2.
+
+ * Note that the Vera family uses minimal delta hinting. Your
+ results on other systems when not used anti-aliased may not be
+ entirely satisfying. We are primarily interested in reports of
+ problems on open source systems implementing Xft2/fontconfig/freetype
+ (which implements antialiasing and hinting adjustements, and
+ sophisticated subpixel decimation on flatpanels). Also, the
+ algorithms used by Xft2 adjust the hints to integer widths and the
+ results are crisper on open source systems than on Windows or
+ MacIntosh.
+
+ * Your fontconfig may (probably does) predate the release of
+ fontconfig 2.2, and you may see artifacts not present when the font is
+ used at very small sizes with hinting enabled. "vc-list -V" can be
+ used to see what version you have installed.
+
+We believe and hope that these fonts will resolve the problems
+reported during beta test. The largest change is the reduction of
+leading (interline spacing), which had annoyed a number of people, and
+reduced Vera's utility for some applcations. The Vera monospace font
+should also now make '0' and 'O' and '1' and 'l' more clearly
+distinguishable.
+
+The version of these fonts is version 1.10. Fontconfig should be
+choosing the new version of the fonts if both the released fonts and
+beta test fonts are installed (though please discard them: they have
+names of form tt20[1-12]gn.ttf). Note that older versions of
+fontconfig sometimes did not rebuild their cache correctly when new
+fonts are installed: please upgrade to fontconfig 2.2. "fc-cache -f"
+can be used to force rebuilding fontconfig's cache files.
+
+If you note problems, please send them to fonts at gnome dot org, with
+exactly which face and size and unicode point you observe the problem
+at. The xfd utility from XFree86 CVS may be useful for this (e.g. "xfd
+-fa sans"). A possibly more useful program to examine fonts at a
+variety of sizes is the "waterfall" program found in Keith Packard's
+CVS.
+
+ $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS login
+ Logging in to :pserver:anoncvs@keithp.com:2401/local/src/CVS
+ CVS password:
+ $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS co waterfall
+ $ cd waterfall
+ $ xmkmf -a
+ $ make
+ # make install
+ # make install.man
+
+Again, please make sure you are running an up-to-date freetype, and
+that you are only examining integer sizes.
+
+Reporting Problems
+==================
+
+Please send problem reports to fonts at gnome org, with the following
+information:
+
+ 1. Version of Freetype, Xft2 and fontconfig
+ 2. Whether TT hinting is being used, or the autohinter
+ 3. Application being used
+ 4. Character/Unicode code point that has problems (if applicable)
+ 5. Version of which operating system
+ 6. Please include a screenshot, when possible.
+
+Please check the fonts list archives before reporting problems to cut
+down on duplication.
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/Vera.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/Vera.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraBI.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraBI.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraBd.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraBd.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraIt.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraIt.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraMoBI.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraMoBI.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraMoBd.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraMoBd.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraMoIt.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraMoIt.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraMono.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraMono.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraSe.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraSe.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/VeraSeBd.ttf
Binary file pycaptcha/Captcha/data/fonts/vera/VeraSeBd.ttf has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/fonts/vera/local.conf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/fonts/vera/local.conf Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+ serif
+
+ Bitstream Vera Serif
+
+
+
+ sans-serif
+
+ Bitstream Vera Sans
+
+
+
+ monospace
+
+ Bitstream Vera Sans Mono
+
+
+
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/.DS_Store
Binary file pycaptcha/Captcha/data/pictures/.DS_Store has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/1.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/1.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/10.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/10.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/11.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/11.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/12.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/12.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/2.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/2.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/3.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/3.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/4.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/4.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/5.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/5.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/6.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/6.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/7.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/7.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/8.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/8.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/9.jpeg
Binary file pycaptcha/Captcha/data/pictures/abstract/9.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/abstract/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/pictures/abstract/README Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,3 @@
+These images were created by the author with Fyre, expressly for PyCAPTCHA.
+
+Copyright (c) 2004 Micah Dowty
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/nature/Craig_Barrington_ocotillo_and_mountains.jpeg
Binary file pycaptcha/Captcha/data/pictures/nature/Craig_Barrington_ocotillo_and_mountains.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/nature/Kerry_Carloy_Chisos_Sunset.jpeg
Binary file pycaptcha/Captcha/data/pictures/nature/Kerry_Carloy_Chisos_Sunset.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/nature/Paul_Dowty_Mt_Bross.jpeg
Binary file pycaptcha/Captcha/data/pictures/nature/Paul_Dowty_Mt_Bross.jpeg has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/pictures/nature/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/pictures/nature/README Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,2 @@
+These are uncopyrighted images gathered from various sources,
+including the author's family and national park service web sites.
\ No newline at end of file
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/words/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/words/README Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,4 @@
+These word lists are from various sources:
+
+basic-english:
+ http://simple.wikipedia.org/wiki/Basic_English_Alphabetical_Wordlist
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/words/basic-english
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/words/basic-english Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,852 @@
+a
+able
+about
+account
+acid
+across
+act
+addition
+adjustment
+advertisement
+agreement
+after
+again
+against
+air
+all
+almost
+among
+amount
+amusement
+and
+angle
+angry
+animal
+answer
+ant
+any
+apparatus
+apple
+approval
+arch
+argument
+arm
+army
+art
+as
+at
+attack
+attempt
+attention
+attraction
+authority
+automatic
+awake
+baby
+back
+bad
+bag
+balance
+ball
+band
+base
+basin
+basket
+bath
+be
+beautiful
+because
+bed
+bee
+before
+behavior
+belief
+bell
+bent
+berry
+between
+bird
+birth
+bit
+bite
+bitter
+black
+blade
+blood
+blow
+blue
+board
+boat
+body
+boiling
+bone
+book
+boot
+bottle
+box
+boy
+brain
+brake
+branch
+brass
+bread
+breath
+brick
+bridge
+bright
+broken
+brother
+brown
+brush
+bucket
+building
+bulb
+burn
+burst
+business
+but
+butter
+button
+by
+cake
+camera
+canvas
+card
+care
+carriage
+cart
+cat
+cause
+certain
+chain
+chalk
+chance
+change
+cheap
+cheese
+chemical
+chest
+chief
+chin
+church
+circle
+clean
+clear
+clock
+cloth
+cloud
+coal
+coat
+cold
+collar
+color
+comb
+come
+comfort
+committee
+common
+company
+comparison
+competition
+complete
+complex
+condition
+connection
+conscious
+control
+cook
+copper
+copy
+cord
+cork
+cotton
+cough
+country
+cover
+cow
+crack
+credit
+crime
+cruel
+crush
+cry
+cup
+current
+curtain
+curve
+cushion
+cut
+damage
+danger
+dark
+daughter
+day
+dead
+dear
+death
+debt
+decision
+deep
+degree
+delicate
+dependent
+design
+desire
+destruction
+detail
+development
+different
+digestion
+direction
+dirty
+discovery
+discussion
+disease
+disgust
+distance
+distribution
+division
+do
+dog
+door
+down
+doubt
+drain
+drawer
+dress
+drink
+driving
+drop
+dry
+dust
+ear
+early
+earth
+east
+edge
+education
+effect
+egg
+elastic
+electric
+end
+engine
+enough
+equal
+error
+even
+event
+ever
+every
+example
+exchange
+existence
+expansion
+experience
+expert
+eye
+face
+fact
+fall
+false
+family
+far
+farm
+fat
+father
+fear
+feather
+feeble
+feeling
+female
+fertile
+fiction
+field
+fight
+finger
+fire
+first
+fish
+fixed
+flag
+flame
+flat
+flight
+floor
+flower
+fly
+fold
+food
+foolish
+foot
+for
+force
+fork
+form
+forward
+fowl
+frame
+free
+frequent
+friend
+from
+front
+fruit
+full
+future
+garden
+general
+get
+girl
+give
+glass
+glove
+go
+goat
+gold
+good
+government
+grain
+grass
+great
+green
+grey/gray
+grip
+group
+growth
+guide
+gun
+hair
+hammer
+hand
+hanging
+happy
+harbor
+hard
+harmony
+hat
+hate
+have
+he
+head
+healthy
+hearing
+heart
+heat
+help
+here
+high
+history
+hole
+hollow
+hook
+hope
+horn
+horse
+hospital
+hour
+house
+how
+humor
+ice
+idea
+if
+ill
+important
+impulse
+in
+increase
+industry
+ink
+insect
+instrument
+insurance
+interest
+invention
+iron
+island
+jelly
+jewel
+join
+journey
+judge
+jump
+keep
+kettle
+key
+kick
+kind
+kiss
+knee
+knife
+knot
+knowledge
+land
+language
+last
+late
+laugh
+law
+lead
+leaf
+learning
+leather
+left
+leg
+let
+letter
+level
+library
+lift
+light
+like
+limit
+line
+linen
+lip
+liquid
+list
+little
+less
+least
+living
+lock
+long
+loose
+loss
+loud
+love
+low
+machine
+make
+male
+man
+manager
+map
+mark
+market
+married
+match
+material
+mass
+may
+meal
+measure
+meat
+medical
+meeting
+memory
+metal
+middle
+military
+milk
+mind
+mine
+minute
+mist
+mixed
+money
+monkey
+month
+moon
+morning
+mother
+motion
+mountain
+mouth
+move
+much
+more
+most
+muscle
+music
+nail
+name
+narrow
+nation
+natural
+near
+necessary
+neck
+need
+needle
+nerve
+net
+new
+news
+night
+no
+noise
+normal
+north
+nose
+not
+note
+now
+number
+nut
+observation
+of
+off
+offer
+office
+oil
+old
+on
+only
+open
+operation
+opposite
+opinion
+other
+or
+orange
+order
+organization
+ornament
+out
+oven
+over
+owner
+page
+pain
+paint
+paper
+parallel
+parcel
+part
+past
+paste
+payment
+peace
+pen
+pencil
+person
+physical
+picture
+pig
+pin
+pipe
+place
+plane
+plant
+plate
+play
+please
+pleasure
+plough/plow
+pocket
+point
+poison
+polish
+political
+poor
+porter
+position
+possible
+pot
+potato
+powder
+power
+present
+price
+print
+prison
+private
+probable
+process
+produce
+profit
+property
+prose
+protest
+public
+pull
+pump
+punishment
+purpose
+push
+put
+quality
+question
+quick
+quiet
+quite
+rail
+rain
+range
+rat
+rate
+ray
+reaction
+red
+reading
+ready
+reason
+receipt
+record
+regret
+regular
+relation
+religion
+representative
+request
+respect
+responsible
+rest
+reward
+rhythm
+rice
+right
+ring
+river
+road
+rod
+roll
+roof
+room
+root
+rough
+round
+rub
+rule
+run
+sad
+safe
+sail
+salt
+same
+sand
+say
+scale
+school
+science
+scissors
+screw
+sea
+seat
+second
+secret
+secretary
+see
+seed
+selection
+self
+send
+seem
+sense
+separate
+serious
+servant
+sex
+shade
+shake
+shame
+sharp
+sheep
+shelf
+ship
+shirt
+shock
+shoe
+short
+shut
+side
+sign
+silk
+silver
+simple
+sister
+size
+skin
+skirt
+sky
+sleep
+slip
+slope
+slow
+small
+smash
+smell
+smile
+smoke
+smooth
+snake
+sneeze
+snow
+so
+soap
+society
+sock
+soft
+solid
+some
+son
+song
+sort
+sound
+south
+soup
+space
+spade
+special
+sponge
+spoon
+spring
+square
+stamp
+stage
+star
+start
+statement
+station
+steam
+stem
+steel
+step
+stick
+still
+stitch
+stocking
+stomach
+stone
+stop
+store
+story
+strange
+street
+stretch
+sticky
+stiff
+straight
+strong
+structure
+substance
+sugar
+suggestion
+summer
+support
+surprise
+such
+sudden
+sun
+sweet
+swim
+system
+table
+tail
+take
+talk
+tall
+taste
+tax
+teaching
+tendency
+test
+than
+that
+the
+then
+theory
+there
+thick
+thin
+thing
+this
+thought
+thread
+throat
+though
+through
+thumb
+thunder
+ticket
+tight
+tired
+till
+time
+tin
+to
+toe
+together
+tomorrow
+tongue
+tooth
+top
+touch
+town
+trade
+train
+transport
+tray
+tree
+trick
+trousers
+true
+trouble
+turn
+twist
+umbrella
+under
+unit
+use
+up
+value
+verse
+very
+vessel
+view
+violent
+voice
+walk
+wall
+waiting
+war
+warm
+wash
+waste
+watch
+water
+wave
+wax
+way
+weather
+week
+weight
+well
+west
+wet
+wheel
+when
+where
+while
+whip
+whistle
+white
+who
+why
+wide
+will
+wind
+window
+wine
+wing
+winter
+wire
+wise
+with
+woman
+wood
+wool
+word
+work
+worm
+wound
+writing
+wrong
+year
+yellow
+yes
+yesterday
+you
+young
\ No newline at end of file
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Captcha/data/words/characters
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Captcha/data/words/characters Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,26 @@
+q
+w
+e
+r
+t
+y
+u
+i
+o
+p
+a
+s
+d
+f
+g
+h
+j
+k
+l
+z
+x
+c
+v
+b
+n
+m
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Facade.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Facade.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+
+
+from Captcha.Visual.Tests import PseudoGimpy, AngryGimpy
+import numpy
+
+# Une fonction simple pour generer un captcha
+# ease : represente la difficulte du captcha a generer
+# 0 = facile et 1 (ou autre chose) = difficile
+#solution : specifie si on veut en retour un array numpy representant
+#l image ou un tuple contenant l'array et la solution du captcha.
+
+# Des fontes additionnelles peuvent etre ajoutees au dossier pyCaptcha/Captcha/data/fonts/others
+# Le programme choisit une fonte aleatoirement dans ce dossier ainsi que le dossir vera.
+
+
+def generateCaptcha (ease=0, solution=0):
+
+ if ease == 1:
+ g = AngryGimpy()
+
+ else:
+ g = PseudoGimpy()
+
+ i = g.render()
+ a = numpy.asarray(i)
+
+ if solution == 0:
+ return a
+
+ else :
+ return (a, g,solutions)
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Facade.pyc
Binary file pycaptcha/Facade.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/Facade.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/Facade.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+
+
+from Captcha.Visual.Tests import PseudoGimpy, AngryGimpy
+import numpy
+
+# Une fonction simple pour generer un captcha
+# ease : represente la difficulte du captcha a generer
+# 0 = facile et 1 (ou autre chose) = difficile
+#solution : specifie si on veut en retour un array numpy representant
+#l image ou un tuple contenant l'array et la solution du captcha.
+
+# Des fontes additionnelles peuvent etre ajoutees au dossier pyCaptcha/Captcha/data/fonts/others
+# Le programme choisit une fonte aleatoirement dans ce dossier ainsi que le dossir vera.
+
+
+def generateCaptcha (ease=0, solution=0):
+
+ if ease == 1:
+ g = AngryGimpy()
+
+ else:
+ g = PseudoGimpy()
+
+ i = g.render()
+ a = numpy.asarray(i)
+
+ if solution == 0:
+ return a
+
+ else :
+ return (a, g,solutions)
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/README Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,51 @@
+======================
+Python CAPTCHA package
+======================
+
+About
+-----
+
+This is the PyCAPTCHA package, a collection of Python modules
+implementing CAPTCHAs: automated tests that humans should pass,
+but current computer programs can't. These tests are often
+used for security.
+
+See http://www.captcha.net for more information and examples.
+
+This project was started because the CIA project, written in
+Python, needed a CAPTCHA to automate its user creation process
+safely. All existing implementations the author could find were
+written in Java or for the .NET framework, so a simple Python
+alternative was needed.
+
+Examples
+--------
+
+Included are several example programs:
+
+ - simple_example.py is a bare-bones example that just generates
+ and displays an image.
+
+ - http_example.py is a longer example that uses BaseHTTPServer
+ to simulate a CAPTCHA's use in a web environment. Running this
+ example and connecting to it from your web browser is a quick
+ and easy way to see PyCAPTCHA in action
+
+ - modpython_example.py is a version of http_example that runs
+ from an Apache server equipped with a properly configured
+ mod_python.
+
+
+Dependencies
+------------
+
+- Python 2.2.1 or later
+- the Python Imaging Library, required for visual CAPTCHAs
+
+
+Contacts
+--------
+
+Micah Dowty
+
+'scanline' on irc.freenode.net
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/http_example.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/http_example.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+#
+# An example that presents CAPTCHA tests in a web environment
+# and gives the user a chance to solve them. Run it, optionally
+# specifying a port number on the command line, then point your web
+# browser at the given URL.
+#
+
+from Captcha.Visual import Tests
+from Captcha import Factory
+import BaseHTTPServer, urlparse, sys
+
+
+class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def do_GET(self):
+ scheme, host, path, parameters, query, fragment = urlparse.urlparse(self.path)
+
+ # Split the path into segments
+ pathSegments = path.split('/')[1:]
+
+ # Split the query into key-value pairs
+ args = {}
+ for pair in query.split("&"):
+ if pair.find("=") >= 0:
+ key, value = pair.split("=", 1)
+ args.setdefault(key, []).append(value)
+ else:
+ args[pair] = []
+
+ # A hack so it works with a proxy configured for VHostMonster :)
+ if pathSegments[0] == "vhost":
+ pathSegments = pathSegments[3:]
+
+ if pathSegments[0] == "":
+ self.handleRootPage(args.get('test', Tests.__all__)[0])
+
+ elif pathSegments[0] == "images":
+ self.handleImagePage(pathSegments[1])
+
+ elif pathSegments[0] == "solutions":
+ self.handleSolutionPage(pathSegments[1], args['word'][0])
+
+ else:
+ self.handle404()
+
+ def handle404(self):
+ self.send_response(404)
+ self.send_header("Content-Type", "text/html")
+ self.end_headers()
+ self.wfile.write("No such resource
")
+
+ def handleRootPage(self, testName):
+ self.send_response(200)
+ self.send_header("Content-Type", "text/html")
+ self.end_headers()
+
+ test = self.captchaFactory.new(getattr(Tests, testName))
+
+ # Make a list of tests other than the one we're using
+ others = []
+ for t in Tests.__all__:
+ if t != testName:
+ others.append('%s' % (t,t))
+ others = "\n".join(others)
+
+ self.wfile.write("""
+
+PyCAPTCHA Example
+
+
+PyCAPTCHA Example
+
+ %s:
+ %s
+
+
+
+
+
+
+
+
+Or try...
+
+
+
+
+
+""" % (test.__class__.__name__, test.__doc__, test.id, test.id, others))
+
+ def handleImagePage(self, id):
+ test = self.captchaFactory.get(id)
+ if not test:
+ return self.handle404()
+
+ self.send_response(200)
+ self.send_header("Content-Type", "image/jpeg")
+ self.end_headers()
+ test.render().save(self.wfile, "JPEG")
+
+ def handleSolutionPage(self, id, word):
+ test = self.captchaFactory.get(id)
+ if not test:
+ return self.handle404()
+
+ if not test.valid:
+ # Invalid tests will always return False, to prevent
+ # random trial-and-error attacks. This could be confusing to a user...
+ result = "Test invalidated, try another test"
+ elif test.testSolutions([word]):
+ result = "Correct"
+ else:
+ result = "Incorrect"
+
+ self.send_response(200)
+ self.send_header("Content-Type", "text/html")
+ self.end_headers()
+ self.wfile.write("""
+
+PyCAPTCHA Example
+
+
+PyCAPTCHA Example
+%s
+
+%s
+You guessed: %s
+Possible solutions: %s
+Try again
+
+
+""" % (test.__class__.__name__, test.id, result, word, ", ".join(test.solutions)))
+
+
+def main(port):
+ print "Starting server at http://localhost:%d/" % port
+ handler = RequestHandler
+ handler.captchaFactory = Factory()
+ BaseHTTPServer.HTTPServer(('', port), RequestHandler).serve_forever()
+
+if __name__ == "__main__":
+ # The port number can be specified on the command line, default is 8080
+ if len(sys.argv) >= 2:
+ port = int(sys.argv[1])
+ else:
+ port = 8080
+ main(port)
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/modpython_example.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/modpython_example.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,113 @@
+#
+# An example that presents CAPTCHA tests in a web environment
+# and gives the user a chance to solve them.
+#
+# This example is for use with Apache using mod_python and its
+# Publisher handler. For example, if your apache configuration
+# included something like:
+#
+# AddHandler python-program .py
+# PythonHandler mod_python.publisher
+#
+# You could place this script anywhere in your web space to see
+# the demo.
+#
+# --Micah
+#
+
+from Captcha.Visual import Tests
+import Captcha
+from mod_python import apache
+
+
+def _getFactory(req):
+ return Captcha.PersistentFactory("/tmp/pycaptcha_%s" % req.interpreter)
+
+
+def test(req, name=Tests.__all__[0]):
+ """Show a newly generated CAPTCHA of the given class.
+ Default is the first class name given in Tests.__all__
+ """
+ test = _getFactory(req).new(getattr(Tests, name))
+
+ # Make a list of tests other than the one we're using
+ others = []
+ for t in Tests.__all__:
+ if t != name:
+ others.append('%s' % (t,t))
+ others = "\n".join(others)
+
+ return """
+
+PyCAPTCHA Example
+
+
+PyCAPTCHA Example (for mod_python)
+
+ %s:
+ %s
+
+
+
+
+
+
+
+
+Or try...
+
+
+
+
+
+""" % (test.__class__.__name__, test.__doc__, test.id, test.id, others)
+
+
+def image(req, id):
+ """Generate an image for the CAPTCHA with the given ID string"""
+ test = _getFactory(req).get(id)
+ if not test:
+ raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND
+ req.content_type = "image/jpeg"
+ test.render().save(req, "JPEG")
+ return apache.OK
+
+
+def solution(req, id, word):
+ """Grade a CAPTCHA given a solution word"""
+ test = _getFactory(req).get(id)
+ if not test:
+ raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND
+
+ if not test.valid:
+ # Invalid tests will always return False, to prevent
+ # random trial-and-error attacks. This could be confusing to a user...
+ result = "Test invalidated, try another test"
+ elif test.testSolutions([word]):
+ result = "Correct"
+ else:
+ result = "Incorrect"
+
+ return """
+
+PyCAPTCHA Example
+
+
+PyCAPTCHA Example
+%s
+
+%s
+You guessed: %s
+Possible solutions: %s
+Try again
+
+
+""" % (test.__class__.__name__, test.id, result, word, ", ".join(test.solutions))
+
+### The End ###
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/output.png
Binary file pycaptcha/output.png has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/setup.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/setup.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+from distutils.core import setup
+from setup.my_install_data import *
+
+setup (name = "PyCAPTCHA",
+ version = "0.4",
+ description = "A Python framework for CAPTCHA tests",
+ maintainer = "Micah Dowty",
+ maintainer_email = "micah@navi.cx",
+ license = "MIT",
+ packages = [
+ 'Captcha',
+ 'Captcha.Visual',
+ ],
+ cmdclass = {
+ 'install_data': my_install_data,
+ },
+ data_files = [Data_Files(
+ preserve_path = 1,
+ base_dir = 'install_lib',
+ copy_to = 'Captcha/data',
+ strip_dirs = 2,
+ template = [
+ 'graft Captcha/data',
+ ],
+ )],
+ )
+
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/setup/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/setup/__init__.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,1 @@
+# Extra modules for use with distutils
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/setup/my_install_data.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/setup/my_install_data.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,191 @@
+"""my_install_data.py
+
+Provides a more sophisticated facility to install data files
+than distutils' install_data does.
+You can specify your files as a template like in MANIFEST.in
+and you have more control over the copy process.
+
+Copyright 2000 by Rene Liebscher, Germany.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Note:
+This licence is only for this file.
+PyOpenGL has its own licence. (it is almost identical.)
+"""
+
+# created 2000/08/01, Rene Liebscher
+
+###########################################################################
+# import some modules we need
+
+import os,sys,string
+from types import StringType,TupleType,ListType
+from distutils.util import change_root
+from distutils.filelist import FileList
+from distutils.command.install_data import install_data
+
+###########################################################################
+# a container class for our more sophisticated install mechanism
+
+class Data_Files:
+ """ container for list of data files.
+ supports alternate base_dirs e.g. 'install_lib','install_header',...
+ supports a directory where to copy files
+ supports templates as in MANIFEST.in
+ supports preserving of paths in filenames
+ eg. foo/xyz is copied to base_dir/foo/xyz
+ supports stripping of leading dirs of source paths
+ eg. foo/bar1/xyz, foo/bar2/abc can be copied to bar1/xyz, bar2/abc
+ """
+
+ def __init__(self,base_dir=None,files=None,copy_to=None,template=None,preserve_path=0,strip_dirs=0):
+ self.base_dir = base_dir
+ self.files = files
+ self.copy_to = copy_to
+ self.template = template
+ self.preserve_path = preserve_path
+ self.strip_dirs = strip_dirs
+ self.finalized = 0
+
+ def warn (self, msg):
+ sys.stderr.write ("warning: %s: %s\n" %
+ ("install_data", msg))
+
+ def debug_print (self, msg):
+ """Print 'msg' to stdout if the global DEBUG (taken from the
+ DISTUTILS_DEBUG environment variable) flag is true.
+ """
+ from distutils.core import DEBUG
+ if DEBUG:
+ print msg
+
+
+ def finalize(self):
+ """ complete the files list by processing the given template """
+ if self.finalized:
+ return
+ if self.files == None:
+ self.files = []
+ if self.template != None:
+ if type(self.template) == StringType:
+ self.template = string.split(self.template,";")
+ filelist = FileList(self.warn,self.debug_print)
+ for line in self.template:
+ filelist.process_template_line(string.strip(line))
+ filelist.sort()
+ filelist.remove_duplicates()
+ self.files.extend(filelist.files)
+ self.finalized = 1
+
+# end class Data_Files
+
+###########################################################################
+# a more sophisticated install routine than distutils install_data
+
+class my_install_data (install_data):
+
+ def check_data(self,d):
+ """ check if data are in new format, if not create a suitable object.
+ returns finalized data object
+ """
+ if not isinstance(d, Data_Files):
+ self.warn(("old-style data files list found "
+ "-- please convert to Data_Files instance"))
+ if type(d) is TupleType:
+ if len(d) != 2 or not (type(d[1]) is ListType):
+ raise DistutilsSetupError, \
+ ("each element of 'data_files' option must be an "
+ "Data File instance, a string or 2-tuple (string,[strings])")
+ d = Data_Files(copy_to=d[0],files=d[1])
+ else:
+ if not (type(d) is StringType):
+ raise DistutilsSetupError, \
+ ("each element of 'data_files' option must be an "
+ "Data File instance, a string or 2-tuple (string,[strings])")
+ d = Data_Files(files=[d])
+ d.finalize()
+ return d
+
+ def run(self):
+ self.outfiles = []
+ install_cmd = self.get_finalized_command('install')
+
+ for d in self.data_files:
+ d = self.check_data(d)
+
+ install_dir = self.install_dir
+ # alternative base dir given => overwrite install_dir
+ if d.base_dir != None:
+ install_dir = getattr(install_cmd,d.base_dir)
+
+ # copy to an other directory
+ if d.copy_to != None:
+ if not os.path.isabs(d.copy_to):
+ # relatiev path to install_dir
+ dir = os.path.join(install_dir, d.copy_to)
+ elif install_cmd.root:
+ # absolute path and alternative root set
+ dir = change_root(self.root,d.copy_to)
+ else:
+ # absolute path
+ dir = d.copy_to
+ else:
+ # simply copy to install_dir
+ dir = install_dir
+ # warn if necceassary
+ self.warn("setup script did not provide a directory to copy files to "
+ " -- installing right in '%s'" % install_dir)
+
+ dir=os.path.normpath(dir)
+ # create path
+ self.mkpath(dir)
+
+ # copy all files
+ for src in d.files:
+ if d.strip_dirs > 0:
+ dst = string.join(string.split(src,os.sep)[d.strip_dirs:],os.sep)
+ else:
+ dst = src
+ if d.preserve_path:
+ # preserve path in filename
+ self.mkpath(os.path.dirname(os.path.join(dir,dst)))
+ out = self.copy_file(src, os.path.join(dir,dst))
+ else:
+ out = self.copy_file(src, dir)
+ if type(out) is TupleType:
+ out = out[0]
+ self.outfiles.append(out)
+
+ return self.outfiles
+
+ def get_inputs (self):
+ inputs = []
+ for d in self.data_files:
+ d = self.check_data(d)
+ inputs.append(d.files)
+ return inputs
+
+ def get_outputs (self):
+ return self.outfiles
+
+
+###########################################################################
+
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/simple_example.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/simple_example.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+# A very simple example that creates a random image from the
+# PseudoGimpy CAPTCHA, saves and shows it, and prints the list
+# of solutions. Normally you would call testSolutions rather
+# than reading this list yourself.
+#
+from Captcha.Visual.Tests import PseudoGimpy, AngryGimpy
+import numpy
+#from numpy import *
+
+#g = AngryGimpy()
+#i = g.render()
+#a = numpy.asarray(i)
+#b = numpy.zeros((2, 2), numpy.int8)
+#c = a == b
+#print c
+#i.save("output.png")
+#i.show()
+#print a
+#print g.solutions
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/simple_example.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/simple_example.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+# A very simple example that creates a random image from the
+# PseudoGimpy CAPTCHA, saves and shows it, and prints the list
+# of solutions. Normally you would call testSolutions rather
+# than reading this list yourself.
+#
+from Captcha.Visual.Tests import PseudoGimpy, AngryGimpy
+import numpy
+#from numpy import *
+
+g = AngryGimpy()
+i = g.render()
+a = numpy.asarray(i)
+b = numpy.zeros((2, 2), numpy.int8)
+c = a == b
+print c
+i.save("output.png")
+i.show()
+#print a
+#print g.solutions
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/test.png
Binary file pycaptcha/test.png has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/transformations.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/transformations.py Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,25 @@
+
+import Numeric, Image
+ #""" Transforme une image PIL en objet numpy.array et vice versa"""
+
+
+def image2array(im):
+ #""" image vers array numpy"""
+ if im.mode not in ("L", "F"):
+ raise ValueError, "can only convert single-layer images"
+ if im.mode == "L":
+ a = Numeric.fromstring(im.tostring(), Numeric.UnsignedInt8)
+ else:
+ a = Numeric.fromstring(im.tostring(), Numeric.Float32)
+ a.shape = im.size[1], im.size[0]
+ return a
+
+def array2image(a):
+ #""" array numpy vers image"""
+ if a.typecode() == Numeric.UnsignedInt8:
+ mode = "L"
+ elif a.typecode() == Numeric.Float32:
+ mode = "F"
+ else:
+ raise ValueError, "unsupported image mode"
+ return Image.fromstring(mode, (a.shape[1], a.shape[0]), a.tostring())
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/transformations.pyc
Binary file pycaptcha/transformations.pyc has changed
diff -r b3d76ebf2fac -r 4775b4195b4b pycaptcha/transformations.py~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pycaptcha/transformations.py~ Thu Feb 11 05:09:46 2010 -0500
@@ -0,0 +1,25 @@
+
+import Numeric, Image
+ """ Transforme une image PIL en objet numpy.array et vice versa"""
+
+
+def image2array(im):
+ """ image vers array numpy"""
+ if im.mode not in ("L", "F"):
+ raise ValueError, "can only convert single-layer images"
+ if im.mode == "L":
+ a = Numeric.fromstring(im.tostring(), Numeric.UnsignedInt8)
+ else:
+ a = Numeric.fromstring(im.tostring(), Numeric.Float32)
+ a.shape = im.size[1], im.size[0]
+ return a
+
+def array2image(a):
+ """ array numpy vers image"""
+ if a.typecode() == Numeric.UnsignedInt8:
+ mode = "L"
+ elif a.typecode() == Numeric.Float32:
+ mode = "F"
+ else:
+ raise ValueError, "unsupported image mode"
+ return Image.fromstring(mode, (a.shape[1], a.shape[0]), a.tostring())