coursera课程字幕批量下载

2012年3月09日 09:44

评论(0) 阅读(2243)

用 PIL 制作 ASCII Art

2012年2月26日 13:22

把每一个字符绘制到一个小的区域中, 然后计算整个区域中的灰白比例, 得到对应的一个参数, 按参数排列得到一个字符按疏密排序后的列表.

import Image, ImageDraw, ImageFont
from itertools import product

def get_data_list():
    fontpath = '/usr/share/fonts/TTF/DejaVuSansMono.ttf'
    fontsize = 20
    h = 24
    w = int(h*0.618)
    charlist = r'''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_=+[{]}\|;:'",<.>/?'''

    def get_char_data(c):
        im = Image.new('L',(w, h),255)
        draw = ImageDraw.Draw(im)
        font = ImageFont.truetype(fontpath, fontsize)
        draw.text((0,0), c, font = font)
        #im.show()
        ans = 0.0
        for i, j in product(range(w), range(h)):
            ans += im.getpixel((i,j))
        return ans / (255.0 * w * h)

    lst = map(lambda c: [c, get_char_data(c)], charlist)
    lst.sort(key=lambda i: i[1])

    return lst


然后把要转换的图片转成灰度, 因为每个字符的宽长比大约是1/2, 所以图片的宽度要先伸展2倍, 然后缩小的一个需要的大小, 用每个像素的灰度值索引到之前算出的列表中的相应字符, 输出即可.

import Image
from pre import get_data_list
from itertools import product

clst = get_data_list()

im = Image.open('stevejobs.png')
size = list(im.size)
size[0]=size[0]/0.5
width = 70
size = (width,int(size[1]/size[0]*width))
im = im.resize(size)
im = im.convert('L')
#im.show()

fo = file('asciiart.txt','w')
for j in range(size[1]):
    for i in range(size[0]):
        idx = int( im.getpixel((i,j)) / 255.0 * (len(clst)-1) )
        fo.write(clst[idx][0])
    fo.write('\n')
fo.close()

效果图:

离远点看, 还是有点意思的~

评论(0) 阅读(1870)

python的闭包和装饰器

2011年12月06日 21:02

  • 闭包(closure)
>>> def F(name):
	def f():
		print name
	return f

>>> f1=F('f1')
>>> f2=F('f2')
>>> f1()
f1
>>> f2()
f2

F 是一个返回函数的函数。对于 F 产生的函数 f1、f2,其依赖于F的本地变量 name,但是在F执行结束后,函数 f1、f2 依然可以访问 name,而且相互独立。就像在返回内层函数时,把产生它的环境一块儿打包返回了,这种语法现象叫闭包(closure)。

在《Programming in Lua 2nd》里展示了闭包的各种绚丽的用法,感觉 lua 把闭包和元编程用到极致了。即使不打算用 lua,也强烈推荐读一读,对了解 python 和其他动态语言的本质和实现或有帮助。

在 lua 中有这样一种写法:

>> function gen_ins(init) 
..   local i=init-1 
..   return function() i=i+1; return i end 
.. end
>> ins5=gen_ins(5)
>> ins2=gen_ins(2)
>> ins5()
=> 5
>> ins2()
=> 2

但是这在 python 中却行不通:

>>> def gen_ins(init):
	i=init-1
	def ins():
		i=i+1
		return i
	return ins

>>> ins0=gen_ins(0)
>>> ins0()

Traceback (most recent call last):
  File "<pyshell#111>", line 1, in <module>
    ins0()
  File "<pyshell#108>", line 4, in ins
    i=i+1
UnboundLocalError: local variable 'i' referenced before assignment

这就是所谓的 python 不支持真闭包,python 中对外层变量不能赋值。一般在 python 的函数中,变量的查找顺序是局部符号表,全局符号表,内置符号表。我们知道,全局变量可以被引用,但是要赋值的话,必须用 global 声明一下,否则其实是新建了一个本地变量。从python解释器的角度看,“i=i+1”中 i 既然被赋值,就应该当做本地变量,所以就会发生上述 UnboundLocalError 错误。i 也并不是全局变量,所以在 ins 中用 global 声明了 i 则会找不到全局变量。按照 PEP3104 来看,这是一个由来已久的问题。

PEP3104 中提到一种解决办法如下:

>>> def gen_ins(init):
	class T: pass
	t=T()
	t.i=init-1
	def ins():
		t.i=t.i+1
		return t.i
	return ins

>>> ins0=gen_ins(0)
>>> ins0()
0

称为"wrapping it in a mutable object",看起来很诡异。因为Guido觉得不能改动关键字 global 的含义,所以在 python 3 中引入了 nonlocal 关键字,总算解决了这个问题。


  • 装饰器(decorators)

前面的闭包算是装饰器的引子了。装饰器有两种形式:

@A
def foo():
    pass

相当于:

def foo():
    pass
foo = A(foo)

而:

@A(arg)
def foo():
    pass

则相当于:

def foo():
    pass
foo = A(arg)(foo)

可以看出第一种的装饰器是个返回函数的函数,第二种的装饰器是个返回 返回函数的函数 的函数。两种装饰器的简单示例:

def A(func):
    def newfunc(*args, **argkw):
        print 'A'
        return func(*args, **argkw)
    return newfunc

def A(arg):
    def _A(func):
        def newfunc(*args, **argkw):
            print arg
            return func(*args, **argkw)
        return newfunc
    return _A

装饰器中的嵌套定义的函数就涉及到 python 中闭包的问题。

装饰器可以做很多事,比如在原函数调用前检查参数,或者检查登陆状态,调用后记录日志什么的。python 中默认有 staticmethod 和 classmethod 两个装饰器。

staticmethod用来声明类的静态方法,这样调用时就不会传入实例对象(self):

>>> class T:
    name = 'T'
    @staticmethod
    def getname():
        print T.name

        
>>> T.getname()
T

classmethod 修饰那些直接以类对象作为参数的方法:

>>> class T:
    name = 'T'
    @classmethod
    def getname(a_class): print a_class.name

    
>>> T.getname()
T

其实更”正常“的是不用装饰器:

>>> def getname(a_class): print a_class.name

>>> class T:
    name = 'T'
    getname = classmethod(getname)

    
>>> T.getname()
T

评论(2) 阅读(4273)

pygame实现文本转图片

2011年11月12日 13:35

渣浪微博上随处可见把大段的文字转成图片发布的。一直以为需要PIL才能实现,今天看到pygame也有这种功能,而且还很简单,看例子:

# coding: utf-8

import pygame
pygame.init()

# 所有可用系统字体
# print pygame.font.get_fonts()

# 字体名, 大小
font = pygame.font.SysFont('microsoftyahei', 16)

# 字儿们, 是否开反锯齿, 前景色, 背景色 
text1 = font.render(u'根据相关法律', True, (0,0,0), (255,255,255))
pygame.image.save(text1, 'text1.jpg')

# 带透明的话不设背景色
text2 = font.render(u'此页无法显示', True, (0,0,0))
pygame.image.save(text2, 'text2.png')

# 组合
w, h = text1.get_size()
surface = pygame.Surface((w, 2*h))
surface.fill((255, 255, 255)) # 因为默认背景黑
surface.blit(text1, (0, 0))
surface.blit(text2, (0, h))
pygame.image.save(surface, 'all.png')

学习自: 用Python和Pygame写游戏-从入门到精通(4)

还可参考这个使用PIL的例子: Python: 纯文本转PNG

评论(0) 阅读(2611)

Google Reader 导出数据搜索预览小工具

2011年11月02日 15:06

updated at 2013/3/14: R.I.P Google Reader.

Google Reader改版了,是好是坏众说纷纭,总之原来那些分享的文章变成冷冰冰的数据包了。在Google悔过之前,我们总不能对着这一个个数据包发呆吧,特别是突然想找什么老文章的时候。所以在大牛 @isnowfy 的启示下有了这个小工具^_^

需要说明的是针对的是“阅读器 JSON”这种数据包,比如 shared-items.json 和 starred-items.json。搜索框里回车可以对标题进行搜索,列表框里单击可以在右侧看到详细信息,比如url地址和去html标签后的网页内容。去html标签使用了BeautifulSoup,所以请自备 BeautifulSoup.py在同一目录下 BeautifulSoup4。由于对Tk(Tkinter)这个古老而恶心的GUI不熟悉,界面上请不要苛责了^_^

附上使用图片和脚本:
reader.png

# coding: utf-8
import json
from Tkinter import *
import tkFileDialog
from bs4 import BeautifulSoup

root = Tk()
e = StringVar()
li, te, data, items = [None]*4
sanitize_all_html = lambda value: BeautifulSoup(value).get_text()


def selectFile():
    global data, items
    filename = tkFileDialog.askopenfilename(parent=root, initialdir='.',
                                            filetypes=[('GR data', '.json')])
    data = json.load(open(filename))
    items = data['items'] if 'items' in data else data
    items = filter(lambda i: 'title' in i, items)
    filterItems()


def filterItems(event=None):
    global data, items
    li.delete(0, END)
    s = e.get()
    for i in items:
        title = i['title']
        try:
            content = ('summary' in i and i['summary']
                                       or i['content'])['content']
        except:
            content = ''
        if s in title or s in content:
            li.insert(END, title)


def showItemInfo(event=None):
    te.delete(1.0, END)
    title = li.get(li.curselection())
    item = filter(lambda i: i['title'] == title, items)[0]
    te.insert(1.0, item['title']+'\n')
    te.insert(2.0, ('author' in item and item['author'] or 'NO AUTHOR')+'\n')
    te.insert(3.0, item['origin']['title']+'\n')
    te.insert(4.0, item['origin']['htmlUrl']+'\n')
    te.insert(5.0, ('alternate' in item and item['alternate'][0]['href'] or
                    'NO URL')+'\n\n')
    if 'summary' in item:
        te.insert(7.0, sanitize_all_html(item['summary']['content'])+'\n')
    else:
        te.insert(7.0, sanitize_all_html(item['content']['content'])+'\n')

f = Frame(root)
lf = Frame(f)
rf = Frame(f)
f.pack(fill='both', expand=1)
lf.pack(side='left', fill='both')
rf.pack(side='left', fill='both', expand=1)

fbt = Button(lf, text="Select file", height=1, command=selectFile)
fbt.pack(side='top', fill=X)

en = Entry(lf, textvariable=e, width=30)
en.bind('<Return>', filterItems)
en.pack(side='top', fill=X)

liy = Scrollbar(lf, orient=VERTICAL)
li = Listbox(lf, yscrollcommand=liy.set)
li.bind('<<ListboxSelect>>', showItemInfo)
liy['command'] = li.yview
li.pack(side='left', fill='both', expand=1)
liy.pack(side='left', fill=Y)

tey = Scrollbar(rf, orient=VERTICAL)
te = Text(rf, yscrollcommand=tey.set, height=30,
          font=('Microsoft Yahei', '12'))
tey['command'] = te.yview
te.pack(side='left', fill='both', expand=1)
tey.pack(side='left', fill=Y)

root.title('GR Data Reader')
root.mainloop()

评论(0) 阅读(1939)