当前位置: 首页 > 工具软件 > pngCanvas > 使用案例 >

python生成png图片_pngCanvas 是一个使用纯Python代码的生成png图像的工具

微生博简
2023-12-01

#!/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"]importos, 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

defblend(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

defintensity(c,i):return [c[0],c[1],c[2],(c[3]*i) >> 8]#compute perceptive grayscale value

defgrayscale(c):return int(c[0]*0.3 + c[1]*0.59 + c[2]*0.11)#compute gradient colors

defgradientList(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)])returngradclassPNGCanvas: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, x0if y0 > y1: y0, y1 =y1, y0return[x0,y0,x1,y1]defverticalGradient(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])defrectangle(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]])deffilledRectangle(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)defcopyRect(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

defline(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-x0if dx <0:

sx= -1

else:

sx= 1dx*=sx

dy= y1-y0#'easy' cases

if dy ==0:for x inrange(x0,x1,sx):

self.point(x, y0)return

if dx ==0:for y inrange(y0,y1):

self.point(x0, y)

self.point(x1, y1)return

if dx ==dy:for x inrange(x0,x1,sx):

self.point(x, y0)

y0= y0 + 1

return

#main loop

self.point(x0, y0)

e_acc=0if dy > dx: #vertical displacement

e = (dx << 16) /dyfor 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 + 1self.point(x0+ sx, y0, intensity(self.color,(0xFF-w)))

self.point(x1, y1)return

#horizontal displacement

e = (dy << 16) /dxfor 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 + 1w= 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)defpolyline(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])defdump(self):

scanlines=bytearray()for y inrange(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', '')defpack_chunk(self,tag,data):

to_check= tag +datareturn struct.pack("!I",len(data)) + to_check + struct.pack("!I", zlib.crc32(to_check) & 0xFFFFFFFF)defload(self,f):assert f.read(8) ==signaturefor tag, data inself.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=0for y inrange(height):

filtertype=ord(raw_data[i])

i= i + 1cur= [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 * 4row=[]

j=0for x inrange(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

returncurelif filtertype == 1: #Sub

xp =0for xc inrange(bpp,len(cur)):

cur[xc]= (cur[xc] + cur[xp]) % 256xp= xp + 1

elif filtertype == 2: #Up

for xc inrange(len(cur)):

cur[xc]= (cur[xc] + prev[xc]) % 256

elif filtertype == 3: #Average

xp =0for xc inrange(len(cur)):

cur[xc]= (cur[xc] + (cur[xp] + prev[xc])/2) % 256xp= xp + 1

elif filtertype == 4: #Paeth

xp =0for i inrange(bpp):

cur[i]= (cur[i] + prev[i]) % 256

for xc inrange(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=aelif pb <=pc:

value=belse:

value=c

cur[xc]= (cur[xc] + value) % 256xp= xp + 1

else:raise TypeError('Unrecognized scanline filter type')returncurdefchunks(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:raiseIOErroryield[tag,data]if __name__ == '__main__':

width= 512height= 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()

 类似资料: