pngCanvas 是一个使用纯Python代码的生成png图像的工具
#!/usr/bin/env python """Simple PNG Canvas for Python - updated for bytearray()"""
__version__ = "1.0.1"
__author__ = "Rui Carmo (http://the.taoofmac.com)"
__copyright__ = "CC Attribution-NonCommercial-NoDerivs 2.0 Rui Carmo"
__contributors__ = ["http://collaboa.weed.rbse.com/repository/file/branches/pgsql/lib/spark_pr.rb"], ["Eli Bendersky"] import os, sys, zlib, struct signature = struct.pack("8B", 137, 80, 78, 71, 13, 10, 26, 10) # alpha blends two colors, using the alpha given by c2
def blend(c1, c2):
return [c1[i]*(0xFF-c2[3]) + c2[i]*c2[3] >> 8 for i in range(3)] # compute a new alpha given a 0-0xFF intensity
def intensity(c,i):
return [c[0],c[1],c[2],(c[3]*i) >> 8] # compute perceptive grayscale value
def grayscale(c):
return int(c[0]*0.3 + c[1]*0.59 + c[2]*0.11) # compute gradient colors
def gradientList(start,end,steps):
delta = [end[i] - start[i] for i in range(4)]
grad = []
for i in range(steps+1):
grad.append([start[j] + (delta[j]*i)/steps for j in range(4)])
return grad class PNGCanvas:
def __init__(self, width, height, bgcolor=bytearray([0xff,0xff,0xff,0xff]),color=bytearray([0,0,0,0xff])):
self.width = width
self.height = height
self.color = color #rgba
self.bgcolor = bgcolor
self.canvas = bytearray(self.bgcolor * 4 * width * height) def _offset(self, x, y):
return y * self.width * 4 + x * 4 def point(self,x,y,color=None):
if x<0 or y<0 or x>self.width-1 or y>self.height-1: return
if color == None:
color = self.color
o = self._offset(x,y)
self.canvas[o:o+3] = blend(self.canvas[o:o+3],bytearray(color)) def _rectHelper(self,x0,y0,x1,y1):
x0, y0, x1, y1 = int(x0), int(y0), int(x1), int(y1)
if x0 > x1: x0, x1 = x1, x0
if y0 > y1: y0, y1 = y1, y0
return [x0,y0,x1,y1] def verticalGradient(self,x0,y0,x1,y1,start,end):
x0, y0, x1, y1 = self._rectHelper(x0,y0,x1,y1)
grad = gradientList(start,end,y1-y0)
for x in range(x0, x1+1):
for y in range(y0, y1+1):
self.point(x,y,grad[y-y0]) def rectangle(self,x0,y0,x1,y1):
x0, y0, x1, y1 = self._rectHelper(x0,y0,x1,y1)
self.polyline([[x0,y0],[x1,y0],[x1,y1],[x0,y1],[x0,y0]]) def filledRectangle(self,x0,y0,x1,y1):
x0, y0, x1, y1 = self._rectHelper(x0,y0,x1,y1)
for x in range(x0, x1+1):
for y in range(y0, y1+1):
self.point(x,y,self.color) def copyRect(self,x0,y0,x1,y1,dx,dy,destination):
x0, y0, x1, y1 = self._rectHelper(x0,y0,x1,y1)
for x in range(x0, x1+1):
for y in range(y0, y1+1):
d = destination._offset(dx+x-x0,dy+y-y0)
o = self._offset(x,y)
destination.canvas[d:d+4] = self.canvas[o:o+4] def blendRect(self,x0,y0,x1,y1,dx,dy,destination,alpha=0xff):
x0, y0, x1, y1 = self._rectHelper(x0,y0,x1,y1)
for x in range(x0, x1+1):
for y in range(y0, y1+1):
o = self._offset(x,y)
rgba = self.canvas[o:o+4]
rgba[3] = alpha
destination.point(dx+x-x0,dy+y-y0,rgba) # draw a line using Xiaolin Wu's antialiasing technique
def line(self,x0, y0, x1, y1):
# clean params
x0, y0, x1, y1 = int(x0), int(y0), int(x1), int(y1)
if y0>y1:
y0, y1, x0, x1 = y1, y0, x1, x0
dx = x1-x0
if dx < 0:
sx = -1
else:
sx = 1
dx *= sx
dy = y1-y0 # 'easy' cases
if dy == 0:
for x in range(x0,x1,sx):
self.point(x, y0)
return
if dx == 0:
for y in range(y0,y1):
self.point(x0, y)
self.point(x1, y1)
return
if dx == dy:
for x in range(x0,x1,sx):
self.point(x, y0)
y0 = y0 + 1
return # main loop
self.point(x0, y0)
e_acc = 0
if dy > dx: # vertical displacement
e = (dx << 16) / dy
for i in range(y0,y1-1):
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
if (e_acc <= e_acc_temp):
x0 = x0 + sx
w = 0xFF-(e_acc >> 8)
self.point(x0, y0, intensity(self.color,(w)))
y0 = y0 + 1
self.point(x0 + sx, y0, intensity(self.color,(0xFF-w)))
self.point(x1, y1)
return # horizontal displacement
e = (dy << 16) / dx
for i in range(x0,x1-sx,sx):
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
if (e_acc <= e_acc_temp):
y0 = y0 + 1
w = 0xFF-(e_acc >> 8)
self.point(x0, y0, intensity(self.color,(w)))
x0 = x0 + sx
self.point(x0, y0 + 1, intensity(self.color,(0xFF-w)))
self.point(x1, y1) def polyline(self,arr):
for i in range(0,len(arr)-1):
self.line(arr[i][0],arr[i][1],arr[i+1][0], arr[i+1][1]) def dump(self):
scanlines = bytearray()
for y in range(self.height):
scanlines.append('\0') # filter type 0 (None)
#print y * self.width * 4, (y+1) * self.width * 4
#print self.canvas[y * self.width * 4:(y+1) * self.width * 4]
scanlines.extend(self.canvas[(y * self.width * 4):((y+1) * self.width * 4)])
# image represented as RGBA tuples, no interlacing
return signature + \
self.pack_chunk('IHDR', struct.pack("!2I5B",self.width,self.height,8,6,0,0,0)) + \
self.pack_chunk('IDAT', zlib.compress(str(scanlines),9)) + \
self.pack_chunk('IEND', '') def pack_chunk(self,tag,data):
to_check = tag + data
return struct.pack("!I",len(data)) + to_check + struct.pack("!I", zlib.crc32(to_check) & 0xFFFFFFFF) def load(self,f):
assert f.read(8) == signature
for tag, data in self.chunks(f):
if tag == "IHDR":
( width,
height,
bitdepth,
colortype,
compression, filter, interlace ) = struct.unpack("!2I5B",data)
self.width = width
self.height = height
self.canvas = bytearray(self.bgcolor * 4 * width * height)
if (bitdepth,colortype,compression, filter, interlace) != (8,6,0,0,0):
raise TypeError('Unsupported PNG format')
# we ignore tRNS for the moment
elif tag == 'IDAT':
raw_data = zlib.decompress(data)
rows = []
i = 0
for y in range(height):
filtertype = ord(raw_data[i])
i = i + 1
cur = [ord(x) for x in raw_data[i:i+width*4]]
if y == 0:
rgba = self.defilter(cur,None,filtertype,4)
else:
rgba = self.defilter(cur,prev,filtertype,4)
prev = cur
i = i + width * 4
row = []
j = 0
for x in range(width):
self.point(x,y,rgba[j:j+4])
j = j + 4 def defilter(self,cur,prev,filtertype,bpp=3):
if filtertype == 0: # No filter
return cur
elif filtertype == 1: # Sub
xp = 0
for xc in range(bpp,len(cur)):
cur[xc] = (cur[xc] + cur[xp]) % 256
xp = xp + 1
elif filtertype == 2: # Up
for xc in range(len(cur)):
cur[xc] = (cur[xc] + prev[xc]) % 256
elif filtertype == 3: # Average
xp = 0
for xc in range(len(cur)):
cur[xc] = (cur[xc] + (cur[xp] + prev[xc])/2) % 256
xp = xp + 1
elif filtertype == 4: # Paeth
xp = 0
for i in range(bpp):
cur[i] = (cur[i] + prev[i]) % 256
for xc in range(bpp,len(cur)):
a = cur[xp]
b = prev[xc]
c = prev[xp]
p = a + b - c
pa = abs(p - a)
pb = abs(p - b)
pc = abs(p - c)
if pa <= pb and pa <= pc:
value = a
elif pb <= pc:
value = b
else:
value = c
cur[xc] = (cur[xc] + value) % 256
xp = xp + 1
else:
raise TypeError('Unrecognized scanline filter type')
return cur def chunks(self,f):
while 1:
try:
length = struct.unpack("!I",f.read(4))[0]
tag = f.read(4)
data = f.read(length)
crc = struct.unpack("!i",f.read(4))[0]
except:
return
if zlib.crc32(tag + data) != crc:
raise IOError
yield [tag,data] if __name__ == '__main__':
width = 512
height = 512
print "Creating Canvas..."
c = PNGCanvas(width,height)
c.color = bytearray([0xff,0,0,0xff])
c.rectangle(0,0,width-1,height-1)
print "Generating Gradient..."
c.verticalGradient(1,1,width-2, height-2,[0xff,0,0,0xff],[0x20,0,0xff,0x80])
print "Drawing Lines..."
c.color = [0,0,0,0xff]
c.line(0,0,width-1,height-1)
c.line(0,0,width/2,height-1)
c.line(0,0,width-1,height/2)
# Copy Rect to Self
print "Copy Rect"
c.copyRect(1,1,width/2-1,height/2-1,1,height/2,c)
# Blend Rect to Self
print "Blend Rect"
c.blendRect(1,1,width/2-1,height/2-1,width/2,0,c)
# Write test
print "Writing to file..."
f = open("test.png", "wb")
f.write(c.dump())
f.close()
# Read test
print "Reading from file..."
f = open("test.png", "rb")
c.load(f)
f.close()
# Write back
print "Writing to new file..."
f = open("recycle.png","wb")
f.write(c.dump())
f.close()
pngCanvas 是一个使用纯Python代码的生成png图像的工具的更多相关文章
- 一个 11 行 Python 代码实现的神经网络
一个 11 行 Python 代码实现的神经网络 2015/12/02 · 实践项目 · 15 评论· 神经网络 分享到:18 本文由 伯乐在线 - 耶鲁怕冷 翻译,Namco 校稿.未经许可,禁止转 ...
- django之分页,纯python代码
Django中分页 py文件代码 """ 自定义分页组件 可以返回分页的数据和分页的HTML代码 """ from django.http ...
- 推荐一个小而美的Python代码格式化工具
代码可读性是评判代码质量的标准之一,有一个衡量代码质量的标准是 Martin 提出的 “WFT” 定律,即每分钟爆出 “WTF” 的次数.你在读别人代码或者做 Code Review 的时候有没有 “ ...
- 调用另一个文件的python代码【转载】
转自:https://blog.csdn.net/u010412719/article/details/47089883 例如我们有a.py和b.py两个文件,当我们需要在b.py文件中应用a.py中 ...
- 【Python 代码】生成hdf5文件
import random from PIL import Image import numpy as np import os import h5py from PIL import Image L ...
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
本文参考:http://www.dabeaz.com/coroutines/ 作者:David Beazley 缘起: 本人最近在学习python的协程.偶然发现了David Beazley的co ...
- Python 代码混淆和加密技术
动机 Python进行商业开发时, 需要有一定的安全意识, 为了不被轻易的逆向. 混淆和加密就有所必要了. 混淆 为了增加代码阅读的难度, 源代码的混淆非常必要, 一个在线的Python代码混淆网站. ...
- Python代码混淆和加密技术
Python进行商业开发时, 需要有一定的安全意识, 为了不被轻易的逆向. 混淆和加密就有所必要了. 为了增加代码阅读的难度, 源代码的混淆非常必要, 一个在线的Python代码混淆网站. http: ...
- 涨见识了,在终端执行 Python 代码的 6 种方式!
原作:BRETT CANNON 译者:豌豆花下猫@Python猫 英文:https://snarky.ca/the-many-ways-to-pass-code-to-python-from-the- ...
随机推荐
- MVC架构中的controller的几种写法
开始写代码之前,我们先来看一下spring MVC概念.一张图能够清晰得说明. 除了controller,我们需要编写大量代码外,其余的都可以通过配置文件直接配置. MVC的本质即是将业务数据的抽取和 ...
- Spring ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
先说:ClassPathXmlApplicationContext 这个类,默认获取的是WEB-INF/classes/下的路径,也就是在myeclipse的src下的路径,所以用这个是获取不到WEB ...
- Response 部分功能
设置状态码的方法: void setStatus(int sc) void setStatus(int sc, String sm) 设置响应头的方法: void setHeade ...
- 《Machine Learning》(第一章)序章
关键词:机器学习,基本术语,假设空间,归纳偏好,机器学习用途 一.机器学习概述 机器学习是一门从数据中,经过计算得到模型(Model)的一种过程,得到的模型不仅能反应出训练数据集中所蕴含的规律,并且能 ...
- 安装mongodb插件
1.安装mngodb模块 wget http://pecl.php.net/get/mongodb-1.2.4.tgz tar zxf mongodb-1.2.4.tgz cd mongodb-1.2 ...
- sshkey改变后出错的解决
错误态 ssh 192.168.111.200 出现如下错误 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING ...
- luogu P1186 玛丽卡
题目描述 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城 ...
- [BZOJ 1407] Savage
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1407 Solution: 由于此题里n的范围很小,因此可以直接从小到大枚举m 那么问题转 ...
- [LOJ6433]最大前缀和
深刻感受到自己的水平和机房里的其他人相差甚远,他们都是随手秒这个题的... $n$很小,考虑状压DP 当一个序列在某个位置取到最大前缀和后,意味着如果把后面的数抽出来单独成序列,那么它的每个前缀和都$ ...
- 【强连通分量缩点】【记忆化搜索】bzoj1589 [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
缩成DAG f(i)表示以i为起点的最长路 #include<cstdio> #include<cstring> #include<algorithm> #incl ...