python学习笔记 -- 03 实现切割九图

废话

朋友问我能不能搞个九图切割的小软件,我就着手搞了
不过这次注释我会用英文写

九图切割

一、需求

  • 选择图片路径
  • 裁剪图片成九张
  • 保存裁剪的九张图片

二、步骤分析

  1. 选择图片
  2. 打开图片
  3. 裁剪图片
  4. 保存裁剪的九张图片
    这里做的途中发现一个小问题,于是中途加了一个步骤,等等说

三、代码框架

我发现写框架是个很好的方式,看的时候不会纠结于具体的语言细节,而是先理清楚程序的功能逻辑

# import modules
from someModule import someMethod


# some functions
def get_pic():
	# get the image from the path given
	pass
	
def cut_pic():
	# cut the picture into 9 picecs
	# the main function of this program
	pass
	
def save_pic():
	# choose path and save the cutted picture
	pass
	
	
# use class to build GUI
# I was mentioned in my last blog
class Main_Function():
	def __init__(self,master):
		# build the body of my GUI
		master
		a Entry() that show the path
		a Button() used to choose path
		a Button() used to begin cut and automatical save
		pass
	def Choose(self):
		# bind to the first button
		# choose pic's path
		pass
	def Cut(self):
		# bind to the second button
		# begin cut and save automatically
		pass


# some basic program
def main():
	root = Tk()
	app = Main_Function(root)
	root.mainloop()

if __name__ == "__main__":
	main()

四、具体填充代码

这是一句鼓励的话:实际学习的时候并不会想看代码一样流程非常轻松地就出来了,我也是从懵逼到查资料到写出代码。
我自己在记录这个流程的时候是尽量保证逻辑连贯性的,所以看上去非常得easy,不过如果自己写代码特备hard的话,不要灰心丧气哈~

import modules部分

GUI采用tkinter,图片处理用PIL

from tkinter import *
from tkinter import filedialog # this is used to choose path
from PIL import Image
get_pic 函数

实现很简单,其实可以直接写在其他函数里,但是写在外面对于整体结构的表达看起来更清楚

def get_pic(pic_path):
	return Image.open(pic_path)
cut_pic函数
def cut_pic(img):
	# use list r_image to save all the pictures cutted
	r_image = []
	# img.size stores the size of the picture
	# [0] is x axis, [1] is y axis
    x = img.size[0]
    y = img.size[1]
    # cut to 9 pieces
    for i in range(3):
        for j in range(3):
        	# use crop to cut
            r_image.append(img.crop((j*x/3,i*y/3,(j+1)*x/3,(i+1)*y/3)))
            # this sentence to confirm that my prgram works correctly
            print("%d th pic cut success" %(i+j*3))
	return r_image

save_pic函数

def save_pic(img):
	# store 9 pictures in order
	for i in range(9):
		img[i] = img[i].resize((128,128))
		# name the picture
		name = "cut_pic_"+str(i)+".png"
		# use save to save
		img[i].save(name)
		# this sectence is used to confirm that my program works correctly
		print("%d th pic save success" % i)
Main_Function
class Main_Function():
    def __init__(self,master):
    	# build the master
        self.master = master
        # set the title
        master.title("PNG Picture Cutter")
        # set the GUI's position
        # get the height and width of the screen
        ws = master.winfo_screenwidth()
        hs = master.winfo_screenheight()
        # calculate the position of x & y
        x = (ws/2)-300
        y = (hs/2)-200
        master.geometry('500x50+%d+%d' % (x,y))
        # can't change the size of the tk()
        master.resizable(False,False)
        
        # the Entry shows the path of the picture
        self.content = Entry(master,width=40)
        # use pack to place the Entry
        self.content.pack(side=LEFT)
        
        # the Button to start cut
        self.CutPic= Button(master,text="Cut",command=self.Cut)
        self.CutPic.pack(side=RIGHT)
        
        # the Button to choose picture's path
        self.ChoosePic = Button(master,text="Choose pic",command=self.Choose)
        self.ChoosePic.pack(side=RIGHT)
		# pack CutPic and ChoosePic in this order to make sure the second button appears in the left.

    def Choose(self):
    	# bind the function to button 1
    	# you can test 'askopenfilename()' in other programe, it's very useful, you will love it.
        self.FilePath = filedialog.askopenfilename()
        # clear the content of the Entry(), make it able for insert
        self.content.delete(0,'end')
        # write the path in the Entry()
        self.content.insert(0,self.FilePath)

    def Cut(self):
    	# use get() to get the content of the Entry()
        path=self.content.get()
        # get the picture
        img = get_pic(path)
        # cut the picture
        r_img = cut_pic(img)
        # save pictures
        save_pic(r_img)

五、功能修正

1.界面布局修正

当时只是纯粹放下了三个控件,想让文本框在左边,choose在中间,cut在右边。简单写了.pack(side=LEFT)这种形式的代码
呈现效果就这么丑……
代码更改前
然后思考了一下该怎么改
可以用一个Frame控件,让Frame控件置中,其他的三个控件在Frame中布局。
这样的pace(side=xxxx)就不会让控件变到最边缘了
代码更改后
这是布局的修改代码:

		# use frame to control the position
		self.frame = Frame(master)
        self.frame.pack()
        # attention!!			↓↓↓
        self.content = Entry(self.frame,width=40)
        self.content.pack(side=LEFT)
        # attention!!			   ↓↓↓
        self.Translate = Button(self.frame,text="Cut",command=self.Cut)
        self.Translate.pack(side=RIGHT)
        # attention!!		    	↓↓↓
        self.ChoosePDF = Button(self.frame,text="Choose pic",command=self.Choose)
        self.ChoosePDF.pack(side=RIGHT)

代码修改后的呈现效果是这样的,美观了很多(自卖自夸)
代码更改后

实际上可以用grid和place直接来布局,但是我还没用到,pack在这里很迅速很简洁

2.空白填补

直接切九图,图片如果原本不是正方形,切出的图片都会是长方形,在朋友圈发图的时候上下边缘会被隐藏。
后来查资料,用resize拉伸图形到统一尺寸。详情见函数save_pic()
试验后发现这种拉伸非常暴力,原本的图片比例会被破坏。
于是想要一种在空白处填补白色的算法,查阅资料后发现了如下代码,构造了fill_image()

def fill_image(image):
	# size[0] is the width, size[1] is the height
    width,height = image.size
    # new_length records the maxmiun between width and height
    new_length = width if width > height else height
    # The Magic Code :)
    # create a white image
    r_image = Image.new(image.mode,(new_length,new_length),color='white')
    # paste the original image to the white background
    if width>height:
        r_image.paste(image,(0,int((new_length-height)/2)))
    else:
        r_image.paste(image,(int((new_length-width)/2),0))
    return r_image

然后在整体代码中添加使用这个函数。
一个位置是可以在button调用cut函数的时候先fill
还有一个位置是可以在外部的函数cut_pic()里先fill
我选择前者,于是修改后的代码如下:

    def Cut(self):
        path=self.content.get()
        # get the picture
        img = get_pic(path)
        # turn to square
        img = fill_image(img)
        # cut the picture
        r_img = cut_pic(img)
        # save pictures
        save_pic(r_img)

六、参考资料

学到了加白边框的方法https://blog.csdn.net/eereere/article/details/79604682
其余资料后期再补,因为搜索地有点杂

七、后记

效果图
救命! 她使用了可爱攻击

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值