前幾天弄了下django的圖片上傳,上傳之后還需要做些簡單的處理,python中PIL模塊就是專門用來做這個事情的。
於是照葫蘆畫瓢做了幾個常用圖片操作,在這里記錄下,以便備用。
這里有個字體文件,大家可以在自己的系統中選取一個,我這打包放在網盤中 下載
一 圖樣
原始圖片

操作一: 縮略圖(通常不用這個方式,因為圖片質量損壞太大)

操作二 : 旋轉圖片中的某一部分

操作三: 給圖片添加一個圖片水印, 2張圖層合並

操作四: 給圖片添加文字水印,這個用的比較多, 我這里弄了個白色通明低,可以弄成完全透明的

操作 五 等比壓縮(比較適合做縮略圖)

操作六 按照比例剪裁之后,等比壓縮,有時候需要定比例的圖片可以這么做

二 代碼
- # -*- encoding=utf-8 -*-
- '''''
- author: orangleliu
- pil處理圖片,驗證,處理
- 大小,格式 過濾
- 壓縮,截圖,轉換
- 圖片庫最好用Pillow
- 還有一個測試圖片test.jpg, 一個log圖片,一個字體文件
- '''
- #圖片的基本參數獲取
- try:
- from PIL import Image, ImageDraw, ImageFont, ImageEnhance
- except ImportError:
- import Image, ImageDraw, ImageFont, ImageEnhance
- def compress_image(img, w=128, h=128):
- '''''
- 縮略圖
- '''
- img.thumbnail((w,h))
- im.save('test1.png', 'PNG')
- print u'成功保存為png格式, 壓縮為128*128格式圖片'
- def cut_image(img):
- '''''
- 截圖, 旋轉,再粘貼
- '''
- #eft, upper, right, lower
- #x y z w x,y 是起點, z,w是偏移值
- width, height = img.size
- box = (width-200, height-100, width, height)
- region = img.crop(box)
- #旋轉角度
- region = region.transpose(Image.ROTATE_180)
- img.paste(region, box)
- img.save('test2.jpg', 'JPEG')
- print u'重新拼圖成功'
- def logo_watermark(img, logo_path):
- '''''
- 添加一個圖片水印,原理就是合並圖層,用png比較好
- '''
- baseim = img
- logoim = Image.open(logo_path)
- bw, bh = baseim.size
- lw, lh = logoim.size
- baseim.paste(logoim, (bw-lw, bh-lh))
- baseim.save('test3.jpg', 'JPEG')
- print u'logo水印組合成功'
- def text_watermark(img, text, out_file="test4.jpg", angle=23, opacity=0.50):
- '''''
- 添加一個文字水印,做成透明水印的模樣,應該是png圖層合並
- http://www.pythoncentral.io/watermark-images-python-2x/
- 這里會產生著名的 ImportError("The _imagingft C module is not installed") 錯誤
- Pillow通過安裝來解決 pip install Pillow
- '''
- watermark = Image.new('RGBA', img.size, (255,255,255)) #我這里有一層白色的膜,去掉(255,255,255) 這個參數就好了
- FONT = "msyh.ttf"
- size = 2
- n_font = ImageFont.truetype(FONT, size) #得到字體
- n_width, n_height = n_font.getsize(text)
- text_box = min(watermark.size[0], watermark.size[1])
- while (n_width+n_height < text_box):
- size += 2
- n_font = ImageFont.truetype(FONT, size=size)
- n_width, n_height = n_font.getsize(text) #文字逐漸放大,但是要小於圖片的寬高最小值
- text_width = (watermark.size[0] - n_width) / 2
- text_height = (watermark.size[1] - n_height) / 2
- #watermark = watermark.resize((text_width,text_height), Image.ANTIALIAS)
- draw = ImageDraw.Draw(watermark, 'RGBA') #在水印層加畫筆
- draw.text((text_width,text_height),
- text, font=n_font, fill="#21ACDA")
- watermark = watermark.rotate(angle, Image.BICUBIC)
- alpha = watermark.split()[3]
- alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
- watermark.putalpha(alpha)
- Image.composite(watermark, img, watermark).save(out_file, 'JPEG')
- print u"文字水印成功"
- #等比例壓縮圖片
- def resizeImg(img, dst_w=0, dst_h=0, qua=85):
- '''''
- 只給了寬或者高,或者兩個都給了,然后取比例合適的
- 如果圖片比給要壓縮的尺寸都要小,就不壓縮了
- '''
- ori_w, ori_h = im.size
- widthRatio = heightRatio = None
- ratio = 1
- if (ori_w and ori_w > dst_w) or (ori_h and ori_h > dst_h):
- if dst_w and ori_w > dst_w:
- widthRatio = float(dst_w) / ori_w #正確獲取小數的方式
- if dst_h and ori_h > dst_h:
- heightRatio = float(dst_h) / ori_h
- if widthRatio and heightRatio:
- if widthRatio < heightRatio:
- ratio = widthRatio
- else:
- ratio = heightRatio
- if widthRatio and not heightRatio:
- ratio = widthRatio
- if heightRatio and not widthRatio:
- ratio = heightRatio
- newWidth = int(ori_w * ratio)
- newHeight = int(ori_h * ratio)
- else:
- newWidth = ori_w
- newHeight = ori_h
- im.resize((newWidth,newHeight),Image.ANTIALIAS).save("test5.jpg", "JPEG", quality=qua)
- print u'等比壓縮完成'
- '''''
- Image.ANTIALIAS還有如下值:
- NEAREST: use nearest neighbour
- BILINEAR: linear interpolation in a 2x2 environment
- BICUBIC:cubic spline interpolation in a 4x4 environment
- ANTIALIAS:best down-sizing filter
- '''
- #裁剪壓縮圖片
- def clipResizeImg(im, dst_w, dst_h, qua=95):
- '''''
- 先按照一個比例對圖片剪裁,然后在壓縮到指定尺寸
- 一個圖片 16:5 ,壓縮為 2:1 並且寬為200,就要先把圖片裁剪成 10:5,然后在等比壓縮
- '''
- ori_w,ori_h = im.size
- dst_scale = float(dst_w) / dst_h #目標高寬比
- ori_scale = float(ori_w) / ori_h #原高寬比
- if ori_scale <= dst_scale:
- #過高
- width = ori_w
- height = int(width/dst_scale)
- x = 0
- y = (ori_h - height) / 2
- else:
- #過寬
- height = ori_h
- width = int(height*dst_scale)
- x = (ori_w - width) / 2
- y = 0
- #裁剪
- box = (x,y,width+x,height+y)
- #這里的參數可以這么認為:從某圖的(x,y)坐標開始截,截到(width+x,height+y)坐標
- #所包圍的圖像,crop方法與php中的imagecopy方法大為不一樣
- newIm = im.crop(box)
- im = None
- #壓縮
- ratio = float(dst_w) / width
- newWidth = int(width * ratio)
- newHeight = int(height * ratio)
- newIm.resize((newWidth,newHeight),Image.ANTIALIAS).save("test6.jpg", "JPEG",quality=95)
- print "old size %s %s"%(ori_w, ori_h)
- print "new size %s %s"%(newWidth, newHeight)
- print u"剪裁后等比壓縮完成"
- if __name__ == "__main__":
- '''''
- 主要是實現功能, 代碼沒怎么整理
- '''
- im = Image.open('test.jpg') #image 對象
- compress_image(im)
- im = Image.open('test.jpg') #image 對象
- cut_image(im)
- im = Image.open('test.jpg') #image 對象
- logo_watermark(im, 'logo.png')
- im = Image.open('test.jpg') #image 對象
- text_watermark(im, 'Orangleliu')
- im = Image.open('test.jpg') #image 對象
- resizeImg(im, dst_w=100, qua=85)
- im = Image.open('test.jpg') #image 對象
- clipResizeImg(im, 100, 200)
三 參考
