为了日后能更加便捷地合成Galgame人物立绘以及CG,摆脱手搓这种效率较低的传统方法,从而彻底解放双手,4月15日,我决定开始长期开发适配各个Galgame引擎合成立绘规则的通用图像处理工具——Galgame Image Cover Tools,简称GICT,由我设计制作,Listder酱提供技术支持。
新的起点
本程序将采用Python语言开发,使用Wxpython库设计UI界面,并提供图片预览、预览图片单张合成以及选择性批量合成的功能。目前计划适配Artemis Engine、Favorite View Point System(FVP)、Siglus Engine以及KiriKiri四大主流Galgame引擎,往后有精力也会适配其它Galgame引擎。
编写基本UI框架
使用Wxpython库编写简单的导入资源界面以及主界面的左右两侧面板并简单创建相应下拉列表和位图控件:
因为Wxpython没有相应的图像预览控件,所以这里定义了一个位图控件,便于后面的图像预览载入:
import wx
###……
class ImageCreateFrame(wx.Frame):
###……
self.image_ctrl = wx.StaticBitmap(self.rightpanel,pos = (x,y))
其中,该控件在面板上的位置会随着预览图象的大小而动态变化,使其居中:
def PartImageCombobox(self,event):
###……
x1 = 360 - image4.size[0] // 2
y1 = 267 - image4.size[1] // 2
self.image_ctrl.Move(x1,y1) ##重新移动位图,使其居中
在制作相关程序的制作者信息以及相关说明时,发现Wxpython基本库里面没有超链接的相关控件,网上大部分给的也是用文本框现手搓出超链接,而且调用Python的webbrowser库会出现连续打开多个网页窗口的BUG。所以,我到Wxpython文档里面查找,找到了一个从来没用过的高级库from wx.lib.agw
,里面就有相应的超链接函数HyperLinkCtrl
,这下问题就解决了:
from wx.lib.agw.hyperlink import HyperLinkCtrl
###……
class AboutFrame(wx.Frame):
###……
self.HyperLink1 = HyperLinkCtrl(panel,-1,"个人博客:岱中鹏的小站 (sgdzp.top)",pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, URL="https://daizhongpeng.sgdzp.top")
但在制作关于界面后,又有新的问题出现了——如果在主窗口里多次按下关于按钮呼出关于界面,Wxpython子窗口会多次打开,重复出现,是一个比较烦人的BUG(特性?)。使用网上大佬们给出的方法,然后进行相应改动,成功阻止了子窗口多开:
import wx
###……
def ClickBtn4(self,event):
for next_frame in wx.GetTopLevelWindows(): #为了防止打开多个相同类型的子窗口,需要在打开子窗口之前检查是否已经存在一个相同类型的子窗口。
if isinstance(next_frame, AboutFrame):
next_frame.Raise() #再次激活子窗口
return #直接结束,避免再次打开一次子窗口
next_frame = AboutFrame()
next_frame.Show()
实现图像预览功能
要想实现图像预览的功能,程序应当是在读取差分文件完成图像合成,产生新的图像后以字节流形式存储在运行内存中,而不是保存在本地(那样和不预览没什么区别……)所以这里使用Python的PIL库进行字节流形式的存储和读取,实现预览效果:
from io import BytesIO
###……
def PartImageCombobox(self,event):
image_stream = BytesIO() #定义字节流
###……
image4.save(image_stream, format='PNG') #以字节流方式存储,避免在本地存储
image_stream.seek(0) #一定要将光标归位!!不然后面会读取出空字节流
wx_image = wx.Image(image_stream, wx.BITMAP_TYPE_ANY) #使用Wxpython中的Image函数读取存储在内存中的字节流
wx_bitmap = wx.Bitmap(wx_image) #创建位图
self.image_ctrl.Show() #显示控件
self.image_ctrl.SetBitmap(wx_bitmap)
self.image_ctrl.SetSize(wx_bitmap.GetSize()) #保证控件大小和预览图象原大小一致
在后面的测试中,发现以原图合成出的图像未免大小(分辨率,也就是比例)都差不多,导致预览图像的时候有很大概率会出界,所以在存储为字节流之前,对合成出的图像按照相应比例进行缩放处理,经过不断调试后,写出了一组比例缩放条件组,这样既能保证图像不会出界,也能提高后面字节流的存储和读取速度:
from PIL import Image
###……
def PartImageCombobox(self,event):
###……
Scaling = float('%.2f'%(image2.size[0] / image2.size[1])) #读取图像比例,保留两位小数
if Scaling>=0.15 and Scaling<0.20:
image4 = image2.resize((60, int(image2.size[1] * 60 / image2.size[0])))
elif Scaling>=0.20 and Scaling<0.25:
image4 = image2.resize((105, int(image2.size[1] * 105 / image2.size[0])))
elif Scaling>=0.25 and Scaling<0.30:
image4 = image2.resize((120, int(image2.size[1] * 120 / image2.size[0])))
elif Scaling>=0.30 and Scaling<0.35:
image4 = image2.resize((145, int(image2.size[1] * 145 / image2.size[0])))
elif Scaling>=0.35 and Scaling<0.40:
image4 = image2.resize((170, int(image2.size[1] * 170 / image2.size[0])))
elif Scaling>=0.40 and Scaling<0.45:
image4 = image2.resize((190, int(image2.size[1] * 190 / image2.size[0])))
elif Scaling>=0.45 and Scaling<0.50:
image4 = image2.resize((200, int(image2.size[1] * 200 / image2.size[0])))
elif Scaling>=0.50 and Scaling<0.55:
image4 = image2.resize((220, int(image2.size[1] * 220 / image2.size[0])))
elif Scaling>=0.55 and Scaling<0.60:
image4 = image2.resize((250, int(image2.size[1] * 250 / image2.size[0])))
elif Scaling>=0.60 and Scaling<0.65:
image4 = image2.resize((300, int(image2.size[1] * 300 / image2.size[0])))
elif Scaling>=0.65 and Scaling<0.70:
image4 = image2.resize((300, int(image2.size[1] * 300 / image2.size[0])))
elif Scaling>=0.70 and Scaling<0.75:
image4 = image2.resize((300, int(image2.size[1] * 300 / image2.size[0])))
elif Scaling>=0.75 and Scaling<0.80:
image4 = image2.resize((300, int(image2.size[1] * 300 / image2.size[0])))
elif Scaling>=0.80 and Scaling<0.85:
image4 = image2.resize((350, int(image2.size[1] * 350 / image2.size[0])))
elif Scaling>=0.85 and Scaling<0.90:
image4 = image2.resize((400, int(image2.size[1] * 400 / image2.size[0])))
elif Scaling>=0.90 and Scaling<0.95:
image4 = image2.resize((420, int(image2.size[1] * 420 / image2.size[0])))
elif Scaling>=0.95 and Scaling<1.00:
image4 = image2.resize((430, int(image2.size[1] * 430 / image2.size[0])))
elif Scaling>=1.00 and Scaling<1.05:
image4 = image2.resize((300, int(image2.size[1] * 300 / image2.size[0])))
elif Scaling>=1.05 and Scaling<1.10:
image4 = image2.resize((470, int(image2.size[1] * 470 / image2.size[0])))
elif Scaling>=1.10 and Scaling<1.15:
image4 = image2.resize((500, int(image2.size[1] * 500 / image2.size[0])))
else:
image4 = image2.resize((500, int(image2.size[1] * 500 / image2.size[0])))
到这里,基本框架就差不多开发完了,后期适配CG合成的时候再进行续写相应UI界面。
接下来,就要开始研究相应Galgame引擎的立绘信息读取和相应图像文件解析以及合成方法了,这也是GICT程序最核心,也是最难的地方了……
总之,任重道远吧。