<gh_stars>10-100
#!/usr/bin/env python
# -*- coding: utf-8 -*-

u'''
An script to crack captchas of `正方教务系统`.
Greatly inspired by "http://www.wausita.com/captcha/"
rewrite by reverland

Usage:

    >>> load_trainset()
    True
    >>> crack_file(u'test1.gif')
    u'48353'
    >>> crack_file(u'test2.gif')
    u'85535'
    >>> crack_buf(open('test3.gif', 'rb').read())
    u'23297'

'''

from __future__ import unicode_literals, division, print_function

import sys
import os
import math
import bz2
import json

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

from PIL import Image

_TRAINSET = []

PKG_PATH = os.path.realpath(os.path.split(__file__)[0])
TRAINSET_FILENAME = 'trainset.json.bz2'


def process_image(im):
    '''Get an image file and return a black-white Image object'''
    im2 = Image.new("P", im.size, 255)
    for x in range(im.size[0]):
        for y in range(im.size[1]):
            pix = im.getpixel((x, y))
            if pix != 212 and pix != 169 and pix != 255 and pix != 40:
                # these are the numbers to get
                im2.putpixel((x, y), 0)
    return im2


def image_from_file(filename):
    im = Image.open(filename)
    return process_image(im.convert('P'))


def image_from_buffer(buf):
    fp = StringIO.StringIO(buf)
    im = Image.open(fp)
    return process_image(im)


def find_letters(im):
    '''Find where letters begin and end'''
    inletter = False
    foundletter = False
    start = 0
    end = 0
    letters = []
    for x in range(im.size[0]):  # slice across
        for y in range(im.size[1]):  # slice down
            pix = im.getpixel((x, y))
            if pix != 255:
                inletter = True
        if foundletter is False and inletter is True:
            foundletter = True
            start = x
        if foundletter is True and inletter is False:
            foundletter = False
            end = x
            letters.append((start, end))
        inletter = False
    return letters


def magnitude(lst):
    '''Calculate for magnitude of a lst'''
    total = 0
    for c in lst:
        total += c ** 2
    return math.sqrt(total)


def relation(lst1, lst2):
    '''Calculate relation between two given list based on vector space theory.
    Truncate when not the same length.'''
    dot_multiply = 0
    if len(lst1) == len(lst2):
        for i in xrange(len(lst1)):
            dot_multiply += lst1[i] * lst2[i]
        cosin = dot_multiply / (magnitude(lst1) * (magnitude(lst2)))
    elif len(lst1) > len(lst2):
        lst1 = lst1[:len(lst2)]
        cosin = relation(lst1, lst2)
    else:
        lst2 = lst2[:len(lst1)]
        cosin = relation(lst1, lst2)
    return cosin


def buildvector(im):
    '''buildvector for Image object, return list'''
    lst = []
    for p in im.getdata():
        lst.append(p)
    return lst


## Functions to crack
def guess(im, trainset):
    '''guess what's the image is and return a tuple (relation, character)'''
    guess = []
    for image in trainset:
        for k, v in image.items():
            guess.append((relation(v, buildvector(im)), k))
    guess.sort(reverse=True)
    return guess[0]


## Crack image
def crack_image(im):
    trainset = _TRAINSET[0]
    letters = find_letters(im)
    results = ''
    for letter in letters:
        im2 = im.crop((letter[0], 0, letter[1], im.size[1]))
        digit = guess(im2, trainset)[1]
        results += digit
    return results


def crack_file(filename):
    '''receive filename and trainset, give out crack result'''

    return crack_image(image_from_file(filename))


def crack_buf(buf):
    '''Crack image stored in a memory buffer.

    The image must be a 60x22 GIF, as generated by the ZFsoft
    system.

    '''

    return crack_image(image_from_buffer(buf))


def load_trainset(filename=TRAINSET_FILENAME):
    if _TRAINSET:
        return True

    path = os.path.join(PKG_PATH, filename)
    with open(path, 'rb') as fp:
        trainset_jsonbz2 = fp.read()

    _TRAINSET.append(json.loads(bz2.decompress(trainset_jsonbz2)))
    return True


# vim:set ai et ts=4 sw=4 sts=4 fenc=utf-8:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

u'''
An script to crack captchas of `正方教务系统`.
Greatly inspired by "http://www.wausita.com/captcha/"
rewrite by reverland

Usage:

    >>> load_trainset()
    True
    >>> crack_file(u'test1.gif')
    u'48353'
    >>> crack_file(u'test2.gif')
    u'85535'
    >>> crack_buf(open('test3.gif', 'rb').read())
    u'23297'

'''

from __future__ import unicode_literals, division, print_function

import sys
import os
import math
import bz2
import json

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

from PIL import Image

_TRAINSET = []

PKG_PATH = os.path.realpath(os.path.split(__file__)[0])
TRAINSET_FILENAME = 'trainset.json.bz2'


def process_image(im):
    '''Get an image file and return a black-white Image object'''
    im2 = Image.new("P", im.size, 255)
    for x in range(im.size[0]):
        for y in range(im.size[1]):
            pix = im.getpixel((x, y))
            if pix != 212 and pix != 169 and pix != 255 and pix != 40:
                # these are the numbers to get
                im2.putpixel((x, y), 0)
    return im2


def image_from_file(filename):
    im = Image.open(filename)
    return process_image(im.convert('P'))


def image_from_buffer(buf):
    fp = StringIO.StringIO(buf)
    im = Image.open(fp)
    return process_image(im)


def find_letters(im):
    '''Find where letters begin and end'''
    inletter = False
    foundletter = False
    start = 0
    end = 0
    letters = []
    for x in range(im.size[0]):  # slice across
        for y in range(im.size[1]):  # slice down
            pix = im.getpixel((x, y))
            if pix != 255:
                inletter = True
        if foundletter is False and inletter is True:
            foundletter = True
            start = x
        if foundletter is True and inletter is False:
            foundletter = False
            end = x
            letters.append((start, end))
        inletter = False
    return letters


def magnitude(lst):
    '''Calculate for magnitude of a lst'''
    total = 0
    for c in lst:
        total += c ** 2
    return math.sqrt(total)


def relation(lst1, lst2):
    '''Calculate relation between two given list based on vector space theory.
    Truncate when not the same length.'''
    dot_multiply = 0
    if len(lst1) == len(lst2):
        for i in xrange(len(lst1)):
            dot_multiply += lst1[i] * lst2[i]
        cosin = dot_multiply / (magnitude(lst1) * (magnitude(lst2)))
    elif len(lst1) > len(lst2):
        lst1 = lst1[:len(lst2)]
        cosin = relation(lst1, lst2)
    else:
        lst2 = lst2[:len(lst1)]
        cosin = relation(lst1, lst2)
    return cosin


def buildvector(im):
    '''buildvector for Image object, return list'''
    lst = []
    for p in im.getdata():
        lst.append(p)
    return lst


## Functions to crack
def guess(im, trainset):
    '''guess what's the image is and return a tuple (relation, character)'''
    guess = []
    for image in trainset:
        for k, v in image.items():
            guess.append((relation(v, buildvector(im)), k))
    guess.sort(reverse=True)
    return guess[0]


## Crack image
def crack_image(im):
    trainset = _TRAINSET[0]
    letters = find_letters(im)
    results = ''
    for letter in letters:
        im2 = im.crop((letter[0], 0, letter[1], im.size[1]))
        digit = guess(im2, trainset)[1]
        results += digit
    return results


def crack_file(filename):
    '''receive filename and trainset, give out crack result'''

    return crack_image(image_from_file(filename))


def crack_buf(buf):
    '''Crack image stored in a memory buffer.

    The image must be a 60x22 GIF, as generated by the ZFsoft
    system.

    '''

    return crack_image(image_from_buffer(buf))


def load_trainset(filename=TRAINSET_FILENAME):
    if _TRAINSET:
        return True

    path = os.path.join(PKG_PATH, filename)
    with open(path, 'rb') as fp:
        trainset_jsonbz2 = fp.read()

    _TRAINSET.append(json.loads(bz2.decompress(trainset_jsonbz2)))
    return True


# vim:set ai et ts=4 sw=4 sts=4 fenc=utf-8:
#!/usr/bin/env python # -*- coding: utf-8 -*- An script to crack captchas of `正方教务系统`. Greatly inspired by "http://www.wausita.com/captcha/" rewrite by reverland  Usage:      >>> load_trainset()     True     >>> crack_file(u'test1.gif')     u'48353'     >>> crack_file(u'test2.gif')     u'85535'     >>> crack_buf(open('test3.gif', 'rb').read())     u'23297' Get an image file and return a black-white Image object # these are the numbers to get Find where letters begin and end # slice across # slice down Calculate for magnitude of a lst Calculate relation between two given list based on vector space theory.     Truncate when not the same length. buildvector for Image object, return list ## Functions to crack guess what's the image is and return a tuple (relation, character) ## Crack image receive filename and trainset, give out crack result Crack image stored in a memory buffer.      The image must be a 60x22 GIF, as generated by the ZFsoft     system. # vim:set ai et ts=4 sw=4 sts=4 fenc=utf-8: