- UID
 - 2443
 - 积分
 - 1311
 - 帖子
 - 78
 - 主题
 - 21
 - 论坛币
 - 909 
 - 威望
 - 8 
 - EP值
 - 449 
 - MP值
 - 0 
 - 阅读权限
 - 100
 - 注册时间
 - 2015-3-7
 - 在线时间
 - 121 小时
 - 最后登录
 - 2018-7-21
  
 
 
 
   
 | 
 本帖最后由 面麻 于 2015-9-10 22:48 编辑  
 
当初我在一个MAD作品里看到的效果,就是拆分字形,想用ASS来实现一下。 
一共2个方法,都是灾厄前辈想的,代码也是他写的。 
我在其中也学到了很多,很感谢灾厄。 
 
可能代码里面有一些东西涉及到高层次的Python语法,尽量看吧。 
注释也很多,如果还有问题,直接跟帖。 
完整工程在下面,可以Prase一下看看。 
 
两种方法可能还有点小bug,各有优劣。 
 
 
test_split_font_temp.zip
(17.56 KB, 下载次数: 5886)
 
 
第一种方法,是拆分矢量字体的绘图代码,先通过 'm' 字符判断大致拆分开,然后再考虑内外框分别是顺时针和逆时针的情况,下面的代码是以逆时针为内框。 
需要说明的是,不同字体,内外框的绕行方向是不确定的,所以如果出现大片字形不正确,可以修改函数check_clockwise()的clockwise值。 
其实,这个判断是比较复杂的,尤其是凹多边形很难判断,如果出现个别字形不正确,只能手动判断和修改绘图代码。- from tcaxPy import *
 
 - from util.gdiFont import *
 
  
- import re
 
  
- def tcaxPy_Init():
 
 -     global font   # Font和GdiFont效果差不多
 
 -     global fontsize
 
 -     global GdiFont
 
 -     fontsize = GetVal(val_FontSize)
 
 -     font = InitFont(GetVal(val_FontFileName), GetVal(val_FaceID), fontsize, GetVal(val_Spacing), GetVal(val_SpaceScale), 0xFFFFFF, 0, 0)
 
 -     GdiFont = gfInitFont(GetVal(val_FontFaceName), fontsize, GetVal(val_Spacing), GetVal(val_SpaceScale), 0, False)   #GDIfont
 
  
- def tcaxPy_User():
 
 -     pass
 
  
 
- def tcaxPy_Fin():
 
 -     FinFont(font)
 
  
- def checkacw(str):          # 判斷內框
 
  
-     Ppath = ppath(str)
 
 -     
 
 -     if Ppath[0]==Ppath[-1]:        #字體矢量有重複最後坐標點的習慣 貌似重複的基本是外框 不過總有bug的地方 總之取首尾不同的 扔掉最後重複
 
 -         Ppath.pop()
 
 -     return check_clockwise(Ppath)   # 设为内框
 
  
- #構建一個本項和後項結合的list 比方說poly為[(1,1),(2,2),(3,3),(4,4)] 則新list為[((1,1),(2,2)),((2,2),(3,3)),((3,3),(4,4)),((4,4),(1,1))]
 
 - def segments(poly):       #網上照搬
 
 -     return zip(poly, poly[1:] + [poly[0]])     
 
  
- def check_clockwise(poly):      #判斷順時針 網上搬 算法之前判斷用的極值求叉積法 總有凹多邊形不準確 這個遍歷所有點算叉積 最後以總和的正負來判斷
 
 -     clockwise = False
 
 -     if (sum(x0*y1 - x1*y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:   # 叉積为負值是逆時針
 
 -         clockwise = not clockwise
 
 -     return clockwise
 
  
 
- def ppath(str):   # 從str 將路徑儲存為 [(1,1),(2,2),(3,3),(4,4)] 這種格式 b 標籤捨棄中間點 做直線考慮
 
 -     if str[0] != 'm':
 
 -         str = 'm'+ str
 
 -     sb = re.split('m|l|b ',str)     # re是一个正则表达式Module,这里的split其实就是字符串的split函数的翻版,只是可以对分隔符用正则
 
 -     ppath = []
 
 -     for s in sb:
 
 -         b = s.split()
 
 -         if len(b) > 1:
 
 -             if b[-1]=='c':
 
 -                 ppath.append((int(b[-3]),int(b[-2])))
 
 -             else:
 
 -                 ppath.append((int(b[-2]),int(b[-1])))
 
 -     ppath.pop()   # 所有路徑 首尾都相同 捨棄掉最後重複
 
 -     return ppath
 
  
- def polycmp(poly1,poly2):    #判斷多邊形是否在另一個多邊形內
 
 -     result = True
 
 -     if poly2[-1]==poly2[0]:
 
 -         poly2.pop()
 
 -     for p1 in poly1:
 
 -         x1,y1= p1
 
 -         if not pointinpoly(x1,y1,poly2):  #遍歷多邊形所有點是否在多邊形內 
 
 -             result = False
 
 -     return result
 
  
- def pointinpoly(x,y,poly): # 判斷一個點是否在多邊形內 網上搬
 
  
-     n = len(poly)
 
 -     inside = False
 
  
-     p1x,p1y = poly[0]
 
 -     for i in range(n+1):
 
 -         p2x,p2y = poly[i % n]
 
 -         if y > min(p1y,p2y):
 
 -             if y <= max(p1y,p2y):
 
 -                 if x <= max(p1x,p2x):
 
 -                     if p1y != p2y:
 
 -                         xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
 
 -                     if p1x == p2x or x <= xints:
 
 -                         inside = not inside
 
 -         p1x,p1y = p2x,p2y
 
  
-     return inside
 
  
 
- def tcaxPy_Main(_i, _j, _n, _start, _end, _elapk, _k, _x, _y, _a, _txt):
 
  
-     ASS_BUF  = []        # used for saving ASS FX lines
 
  
-     #############################
 
 -     # TODO: write your codes here #
 
  
-     dx = _x - int(_a / 2 + 0.5)
 
 -     dy = _y - int(fontsize / 2 + 0.5)
 
  
-     outline = gfGetOutline(GdiFont, _txt, dx,dy)
 
  
-     draw = outline.split('m')
 
 -     num = len(draw)
 
 -     tcaxLog(draw)
 
  
 
-     acdl = []   #用來儲存內框矢量
 
 -     cdl = []    #儲存外框矢量
 
 -     if _i>-1 :
 
 -         for i in range(num):     #遍歷所有m標籤矢量 判斷內外框 并進行儲存
 
 -             if draw[i] == '':
 
 -                 continue
 
 -  
 
 -             if checkacw(draw[i]):     
 
 -                 acd = 'm'+draw[i]
 
 -                 acdl.append(acd)
 
 -             else:
 
 -                 cd = 'm'+draw[i] 
 
 -                 cdl.append(cd)   
 
 -    
 
 -     cdlcopy = cdl[:]   #複製一遍list
 
 -     for acd in acdl:    
 
 -         index = -1
 
 -         for i in range(len(cdlcopy)):
 
 -             if polycmp(ppath(acd),ppath(cdlcopy[i])):     #遍歷所有內框外框 判斷內框是否在外框範圍內
 
 -                 if index == -1:
 
 -                     index = i
 
 -                 else:                                    
 
 -                     if polycmp(ppath(cdlcopy[i]),ppath(cdlcopy[index])):   #若存在多個可匹配的範圍 取最小的框 如"回"字
 
 -                         index = i
 
 -         if index != -1:
 
 -             cdl[index] += acd    #將內框矢量 加在外框矢量之後
 
 -         else:
 
 -             cdl.append(acd)  #若沒找到匹配的外框 則作為外框 這個有可能是順時針逆時針的判斷問題 也有可能是字體設計的問題 總之是保險
 
  
-     for cd in cdl:   #繪製
 
 -         posX = randint(-_a, _a) + randint(-10, 10)
 
 -         posY = randint(-fontsize , fontsize ) + randint(-10, 10)
 
 -         EFT = an(7) + move(posX, posY, 0, 0, 0, 500) + p(4)
 
 -         ass_main(ASS_BUF, SubL(_start, _end), EFT, cd)
 
  
-     #############################
 
  
-     return (ASS_BUF, None)
 
  复制代码 第二种方法,是用粒子,这里面用到了判断连通性的Labeling算法,网络上搜索 'Labeling' 就可以找到相关资料,比如:http://blog.csdn.net/icvpr/article/details/10259577 
具体的算法不做解释,但还是需要自己查看一下才能看懂下面的代码。- from tcaxPy import *
 
  
- def tcaxPy_Init():
 
 -     global font
 
 -     global fontsize
 
  
-     fontsize = GetVal(val_FontSize)
 
 -     font = InitFont(GetVal(val_FontFileName), GetVal(val_FaceID), fontsize, GetVal(val_Spacing), GetVal(val_SpaceScale), 0xFFFFFF, 0, 0)
 
  
 
- def tcaxPy_User():
 
 -     pass
 
  
 
- def tcaxPy_Fin():
 
 -     FinFont(font)
 
  
- def GetPixelPointFromPix(PIX, InitPosX, InitPosY):      # 将方形PIX[1][0]xPIX[1][1]范围的pixel扫描成一个list,保存位置、RGBA、label信息
 
 -     pixel = []
 
 -     label = 0
 
 -     for h in range(PIX[1][1]):
 
 -         posY = InitPosY + h
 
 -         for w in range(PIX[1][0]):
 
 -             posX = InitPosX + w
 
 -             idx = 4 * (h * PIX[1][0] + w)
 
 -             pixR = PIX[2][idx + 0]
 
 -             pixG = PIX[2][idx + 1]
 
 -             pixB = PIX[2][idx + 2]
 
 -             pixA = PIX[2][idx + 3]
 
 -             pixel.append([(posX, posY), (pixR, pixG, pixB, pixA), label])
 
 -     
 
 -     return pixel
 
  
- def DeleteRepeat(labelset):     # 删除list中的重复元素
 
  
-     labelset2 = []
 
  
-     [labelset2.append(label) for label in labelset if not label in labelset2]
 
  
-     return labelset2      
 
  
 
- def UnionTwoLists(list1, list2):     # 合并2个list,默认它们含有相同元素
 
 -     for elem in list1:
 
 -         if elem in list2:
 
 -             continue
 
 -         else:
 
 -             list2.append(elem)
 
  
-     return list2
 
  
 
- def UnionLabelSet(labelset):        # 整理labelset,合并
 
 -     labelset = sorted(labelset, key=lambda k: k[0]) # 排序
 
 -     labelset = DeleteRepeat(labelset) # 刪除重複
 
  
-     labelset2 = []
 
  
 
-     for label in labelset:
 
 -         if labelset2 == []:               #第一個 label 直接添加
 
 -             labelset2.append(label) 
 
  
-         else:
 
 -             flag = 0
 
 -             for i in range(len(labelset2)):   #遍歷之前的label找交集 若存在交集 向對應位置 添加未存在的元素
 
 -                 #tcaxLog(label2) 
 
 -                 if (label[0] not in labelset2[i]) and (label[1] in labelset2[i]): 
 
 -                     flag = 1
 
 -                     labelset2[i].append(label[0])
 
 -                 elif (label[0] in labelset2[i]) and (label[1] not in labelset2[i]):
 
 -                     flag = 1
 
 -                     labelset2[i].append(label[1])
 
 -                 elif (label[0] in labelset2[i]) and (label[1] in labelset2[i]):
 
 -                     flag = 1
 
 -             if flag == 0:   # 若不存在交集 則另存
 
 -                 labelset2.append(label)
 
  
-     #tcaxLog(labelset2)           
 
 -     return labelset2
 
 -     
 
  
- def tcaxPy_Main(_i, _j, _n, _start, _end, _elapk, _k, _x, _y, _a, _txt):
 
  
-     ASS_BUF  = []        # used for saving ASS FX lines
 
  
-     #############################
 
 -     # TODO: write your codes here #
 
  
-     PIX = TextPix(font, _txt)
 
  
-     InitPosX = _x - int(_a / 2 + 0.5) + PIX[0][0]
 
 -     InitPosY = _y - int(fontsize / 2 + 0.5) + PIX[0][1]
 
  
-     pixel = GetPixelPointFromPix(PIX, InitPosX, InitPosY)
 
  
-     num = len(pixel)
 
 -     label = 0
 
 -     labelset = []
 
  
-     # 1-pass
 
 -     for i in range(num):
 
 -         if pixel[i][1][3] != 0:     # 如果是有效像素
 
 -             if i == 0:              # 如果是第1个像素,没有左面和上面的相邻像素,需要单独考虑
 
 -                 label += 1
 
 -                 pixel[i][2] = label
 
 -             elif i % PIX[1][0] == 0:                # 如果是第1列像素,没有左面的相邻像素,需要单独考虑
 
 -                 uppixelindex = i - PIX[1][0]        # 取上面的相邻像素index
 
 -                 if pixel[uppixelindex][2] != 0:      
 
 -                     pixel[i][2] = pixel[uppixelindex][2]    # 如果上面的相邻像素是有效像素,就把上面像素的label赋给当前像素
 
 -                 else:                                       # 如果上面的相邻像素不是有效像素,就把label加1,然后赋给当前像素
 
 -                     label += 1
 
 -                     pixel[i][2] = label
 
 -             elif i <= PIX[1][0] - 1:        # 如果是第1行像素,没有上面的相邻像素,需要单独考虑
 
 -                 leftpixelindex = i - 1
 
 -                 if pixel[leftpixelindex][2] != 0:
 
 -                     pixel[i][2] = pixel[leftpixelindex][2]
 
 -                 else:
 
 -                     label += 1
 
 -                     pixel[i][2] = label
 
 -             else:                           # 同时考虑上面和左面的相邻像素是否是有效像素
 
 -                 uppixelindex = i - PIX[1][0]
 
 -                 leftpixelindex = i - 1
 
 -                 if pixel[leftpixelindex][2] != 0 and pixel[uppixelindex][2] != 0:                   # 如果上面和左面的相邻像素都是有效像素,
 
 -                     pixel[i][2] = min(pixel[leftpixelindex][2], pixel[uppixelindex][2])             # 就把它们的label的最小值赋给当前像素
 
 -                     if pixel[leftpixelindex][2] != pixel[uppixelindex][2]:                          # 如果它们的label不相等,
 
 -                         labelset.append(sorted([pixel[leftpixelindex][2], pixel[uppixelindex][2]])) # 就把它们的label组成一个list加入labelset
 
 -                 elif pixel[leftpixelindex][2] != 0 and pixel[uppixelindex][2] == 0:                 # 如果上面的相邻像素不是有效像素,
 
 -                     pixel[i][2] = pixel[leftpixelindex][2]                                          # 就把左面像素的label赋给相邻像素
 
 -                 elif pixel[leftpixelindex][2] == 0 and pixel[uppixelindex][2] != 0:                 # 如果左面的相邻像素不是有效像素,
 
 -                     pixel[i][2] = pixel[uppixelindex][2]                                            # 就把上面像素的label赋给相邻像素
 
 -                 else:                                                                               # 如果如果上面和左面的相邻像素都不是有效像素,
 
 -                     label += 1                                                                      # 把label加1,赋给当前像素
 
 -                     pixel[i][2] = label
 
 -     #tcaxLog(pixel)                                        
 
 -     labelset = UnionLabelSet(labelset)        
 
  
-     #print(labelset)                        
 
 -       
 
 -     # 2-pass    #這個地方寫法冗長 比較亂 沒仔細想
 
  
-     for i in range(len(pixel)):   #按labelset 修改相同 label
 
 -         if pixel[i][2] != 0:
 
 -             for j in range(len(labelset)):
 
 -                 if pixel[i][2] in labelset[j]:                                            
 
 -                     pixel[i][2] = min(labelset[j])
 
 -                  
 
 -     #tcaxLog(min(labelset[j]))
 
 -     rndx = []
 
 -     rndy = []
 
 -     cor = []
 
 -     labelbuf = []
 
  
-     for i in range(len(pixel)):   # 將不連續的label修改成最小連續數列
 
  
-         label = pixel[i][2]
 
 -         if label != 0:
 
 -             if label not in labelbuf:
 
 -                 labelbuf.append(label)
 
 -             pixel[i][2] = labelbuf.index(label) +1
 
  
 
-     for i in range(len(labelbuf)):  # 按照label個數生成隨機位置和顏色list
 
 -         rndx.append(randint(-50, 50))
 
 -         rndy.append(randint(-100, 100))
 
 -         cor.append(RandRGB())
 
  
-     #tcaxLog(sorted(labelbuf))
 
  
-     #if _i == 0 and _j == 2:
 
 -     #    tcaxLog(pixel)
 
 -   
 
 -     for i in range(len(pixel)):   #繪製  
 
 -         label = pixel[i][2]
 
  
-         if label != 0:
 
  
-             EFT = move(pixel[i][0][0] + rndx[label-1], pixel[i][0][1] + rndy[label-1], pixel[i][0][0], pixel[i][0][1], 0, 500) + alpha(255 - pixel[i][1][3]) + color1(cor[label-1])
 
 -             ass_main(ASS_BUF, SubL(_start, _end, 0, Pix_Style), EFT, DrawPoint())
 
  
 
-     #############################
 
  
-     return (ASS_BUF, None)
 
  复制代码 |   
 
- 
6
查看全部评分 
 
- 
 
 
  
 |