一、背景
前天在給微信公眾號上傳文章的時候,文章里面有一個圖片是gif的,在上傳的過程中報錯了,說是圖片超大了。搜索之后發現圖片需要小于5m。
那么問題就轉化為怎么把當前的gif給縮減到5m以內本著有輪子用輪子,沒有輪子造輪子的精神,網上搜索一番。
發現一些現象
1、壓縮要不就是需要會員才能下載;
2、要不免費的只能壓縮5m以下的。
考慮到能動手不花錢的本性,我覺得要自己搞一下。
知識背景:
眾所周知,gif圖就是由若干組圖片組成的一種文件格式,有多張有一定差異的圖片連續播放,間隔時間較小,欺騙了我們的眼睛和大腦,然后我們以為是一個完全連續的。其實就是一個類似快速翻書的操作。
二、方案選型
方案一
因為gif是有多種圖片做的,那我們就考慮把圖片減少一些,比如說原來是100張是10m,我給縮減到10張,那體積可不就要縮小到1m左右了嗎?當然,為了用戶看起來不是那么卡頓,我就拍腦袋給縮減到20張吧,即只有原來的1/5。
方案二
如果縮減的圖片太多導致gif看起來卡頓的話,我們可以考慮不縮減圖片的張數,但是我們可以壓縮圖片。
方案三
最后的都是重要的,如果前面兩個都無法滿足的話,那就可以考慮把他們進行疊加。先減張數,再壓縮拆分的圖片。
三、項目落實
整體流程如下:
if__name__=="__main__": #設置源gif的地址 sourceGifPath="/Users/user/test/f79a3e2c2e864863a6b1a66791cb0950_tplv-k3u1fbpfcp-watermark.gif" #將gif拆分成多個圖片,并保存在本地 SplitGif(sourceGifPath) #將指定位置的文件下的圖片按照文件名索引排序,做成gif Combine2Gif(sourceGifPath[:-4],sourceGifPath[:-4]+"_result.gif") print("==finished==")1、將源gif讀入內存
2、將gif拆分成png,并保存
defSplitGif(gifPath): #獲取png存儲的文件夾的地址 pngDir=gifPath[:-4] #要存儲的文件夾下清理干凈,避免影響當前操作 rmPngDir(pngDir) #創建存儲的文件夾 os.mkdir(pngDir) #把指定gif拆分后存儲到指定文件夾 savePngToDir(gifPath,pngDir)2.1、獲取要存儲的地址
2.2、清空并移除存儲png的文件夾
defrmPngDir(pngDir): ifos.path.exists(pngDir): files=os.listdir(pngDir) #如果不一個一個的移除文件夾下的文件的話,無法移除文件夾 forfileinfiles: file=pngDir+"/"+file os.remove(file) os.rmdir(pngDir)2.3、創建存儲png的文件夾
2.4、將gif拆分成png,并保存
defsavePngToDir(gifPath,pngDir): #通過路徑傳教image對象 image=Image.open(gifPath) try: #循環,通過異常方案退出循環 whileTrue: #獲取當前的索引的位置 current=image.tell() #創建文件路徑 pngPath=pngDir+'/'+str(current)+'.png' image.save(pngPath,quality=100) #索引后移,越界后異常,退出當前循環 image.seek(current+1) exceptEOFErrorase: print(e) pass3、按照一定的間隔讀取2中的png,并生成gif
defCombine2Gif(folderPath,gifFilePath): GenerateGif(0.1,gifFilePath,getPngArray(folderPath))3.1、獲取所有的png
defgetPngArray(folderPath): files=os.listdir(folderPath) pngFiles=[] #通過設置step,將文件的大小修改為原來的體積的1/step foriinrange(0,len(files),5): pngFiles.append(folderPath+"/"+('%d.png'%i)) returnpngFiles3.2、將png合并成gif
defGenerateGif(step,gifPath,filterPngs): images=[] forfilePathinfilterPngs: images.append(imageio.imread(filePath)) #生成gif,duration是播放兩個圖片之間的間隔時間 imageio.mimsave(gifPath,images,duration=step)四、全部的代碼
#!/usr/local/bin/python3 #-*-coding:utf-8-*- fromPILimportImage importos importimageio defSplitGif(gifPath): #獲取png存儲的文件夾的地址 pngDir=gifPath[:-4] #要存儲的文件夾下清理干凈,避免影響當前操作 rmPngDir(pngDir) #創建存儲的文件夾 os.mkdir(pngDir) #把指定gif拆分后存儲到指定文件夾 savePngToDir(gifPath,pngDir) defrmPngDir(pngDir): ifos.path.exists(pngDir): files=os.listdir(pngDir) #如果不一個一個的移除文件夾下的文件的話,無法移除文件夾 forfileinfiles: file=pngDir+"/"+file os.remove(file) os.rmdir(pngDir) defsavePngToDir(gifPath,pngDir): #通過路徑傳教image對象 image=Image.open(gifPath) try: #循環,通過異常方案退出循環 whileTrue: #獲取當前的索引的位置 current=image.tell() #創建文件路徑 pngPath=pngDir+'/'+str(current)+'.png' image.save(pngPath,quality=100) #索引后移,越界后異常,退出當前循環 image.seek(current+1) exceptEOFErrorase: print(e) pass defCombine2Gif(folderPath,gifFilePath): GenerateGif(0.1,gifFilePath,getPngArray(folderPath)) #獲取文件的數組 defgetPngArray(folderPath): files=os.listdir(folderPath) pngFiles=[] #通過設置step,將文件的大小修改為原來的體積的1/step foriinrange(0,len(files),5): pngFiles.append(folderPath+"/"+('%d.png'%i)) returnpngFiles defGenerateGif(step,gifPath,filterPngs): images=[] forfilePathinfilterPngs: images.append(imageio.imread(filePath)) #生成gif,duration是播放兩個圖片之間的間隔時間 imageio.mimsave(gifPath,images,duration=step) if__name__=="__main__": #設置源gif的地址 sourceGifPath="/Users/user/test/f79a3e2c2e864863a6b1a66791cb0950_tplv-k3u1fbpfcp-watermark.gif" #將gif拆分成多個圖片,并保存在本地 SplitGif(sourceGifPath) #將指定位置的文件下的圖片按照文件名索引排序,做成gif Combine2Gif(sourceGifPath[:-4],sourceGifPath[:-4]+"_result.gif") print("==finished==")五、結尾
作為一個追求高效的程序員,我就做一個能滿足我需求的方案,即方案一。至于方案二和方案三,有興趣的朋友可以舉一反三。
以上內容為大家介紹了如何使用Python對GIF進行壓縮,希望對大家有所幫助,如果想要了解更多Python相關知識,請關注IT培訓機構:千鋒教育。http://www.dietsnews.net/