#!/usr/bin/env python
# -*- coding: utf-8 -*-
########################################################################
# version 1.0.0
#
# GimpPythonFuVerticalWriting-2-8.py
# Copyright (C) 2013 かんら・から http://www.pixiv.net/member.php?id=3098715
#
# GimpPythonFuVerticalWriting-2-8.py is Python-fu plugin for GIMP 2.8
#
# GimpPythonFuVerticalWriting-2-8.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GimpPythonFuVerticalWriting-2-8.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see .
#
# GPLv3 ライセンス
# かんら・から http://www.pixiv.net/member.php?id=3098715
# バグレポート・アイデアなどは pixiv メッセージでお願いします。
#
# ダウンロード
# http://www.magic-object.mydns.jp/
#
# このスクリプトを使用して発生した問題に関し、作成者は如何なる保証などを行う事はありません。
# 自己責任でのみの使用を許可します。
########################################################################
from gimpfu import *
import gimpcolor
import gimpui
import gtk
import gobject
import re
import math
import xml.dom.minidom
# import chardet
import os
import ConfigParser
import pygtk
pygtk.require('2.0')
########################################################################
########################################################################
# Pangoクラス
#
# Pango を操作する
#
########################################################################
class PangoAccess:
########################################################################
document = None
fontList = []
lines = []
########################################################################
defaultFont = 'Sans'
########################################################################
def __init__(self, markUp, defaultText=None):
if markUp:
markUp = markUp.rstrip()
try:
self.document = xml.dom.minidom.parseString(markUp)
except:
self.document = xml.dom.minidom.parseString('')
if defaultText:
defaultText = defaultText.rstrip()
textNode = self.document.createTextNode(defaultText)
self.document.firstChild.appendChild(textNode)
elif markUp:
textNode = self.document.createTextNode(markUp)
self.document.firstChild.appendChild(textNode)
else:
self.document = xml.dom.minidom.parseString('')
if defaultText:
textNode = self.document.createTextNode(defaultText)
self.document.firstChild.appendChild(textNode)
self.parse()
########################################################################
def __del__(self):
if self.document:
self.document.unlink()
########################################################################
def getAllText(self):
if not self.document:
return ''
########################################################################
return self.getTextNodeValue(self.document.firstChild)
########################################################################
def toUnicode(self, text):
if isinstance(text, unicode):
return text
if not isinstance(text, str):
text = str(text)
# codecInfo = chardet.detect( text )
# return unicode( text, codecInfo['encoding'] )
try:
return unicode(text, 'utf-8')
except:
pass
try:
return unicode(text, 'euc-jp')
except:
pass
try:
return unicode(text, 'cp932')
except:
return text
########################################################################
def getTextNodeValue(self, element):
if not element:
return ''
elif element.nodeType == element.TEXT_NODE:
return element.nodeValue
elif element.nodeType != element.ELEMENT_NODE:
return ''
########################################################################
text = ''
for node in element.childNodes:
if node.hasChildNodes():
text += self.getTextNodeValue(node)
elif node.nodeType == node.TEXT_NODE:
text += node.nodeValue
########################################################################
return text
########################################################################
def setFontList(self, fontList):
self.fontList = sorted(fontList)
########################################################################
def getFontName(self, name, bold=False, italic=False):
if name not in self.fontList:
return name
########################################################################
regExpBoldItalic = re.compile('( bold italic$)|( italic bold$)|(-P?BI?$)', re.IGNORECASE)
regExpBold = re.compile('( bold$)|(-P?B$)', re.IGNORECASE)
regExpItalic = re.compile('( italic$)|(-I$)', re.IGNORECASE)
if bold and italic:
if regExpBoldItalic.search(name):
return name
elif bold:
if regExpBold.search(name):
return name
elif italic:
if regExpItalic.search(name):
return name
########################################################################
orgFontName = re.sub('-[PBSI]+$', '', name)
regExpBoldItalic = re.compile('^(' + re.escape(orgFontName) + '\\s*)(' + regExpBoldItalic.pattern + ')',
regExpBoldItalic.flags)
regExpBold = re.compile('^(' + re.escape(orgFontName) + '\\s*)(' + regExpBold.pattern + ')', regExpBold.flags)
regExpItalic = re.compile('^(' + re.escape(orgFontName) + '\\s*)(' + regExpItalic.pattern + ')',
regExpItalic.flags)
########################################################################
for fontName in self.fontList:
if bold and italic:
if regExpBoldItalic.search(fontName):
return fontName
elif bold:
if regExpBold.search(fontName):
return fontName
elif italic:
if regExpItalic.search(fontName):
return fontName
########################################################################
return name
########################################################################
def setDefaultFont(self, font):
self.defaultFont = font
########################################################################
def parse(self):
self.lines = []
if not self.document:
return self.lines
########################################################################
nodeList = self.document.firstChild.childNodes
for node in nodeList:
self.parseNode(node, self.defaultFont, False, False, {})
########################################################################
def parseNode(self, node, font=None, bold=False, italic=False, attribute={}):
if not node:
return
if not isinstance(node, xml.dom.minidom.Node):
return
if node.nodeType == node.TEXT_NODE:
self.wordAdd(node.nodeValue, font, bold, italic, attribute)
return
elif node.nodeType == node.ELEMENT_NODE:
if not node.hasChildNodes():
return
elif node.tagName.lower() == 'b':
bold = True
elif node.tagName.lower() == 'i':
italic = True
elif node.tagName.lower() == 's':
attribute['strikethrough'] = True
elif node.tagName.lower() == 'u':
attribute['underline'] = 'single'
elif node.tagName.lower() == 'span':
if node.attributes:
for index in range(node.attributes.length):
attrNode = node.attributes.item(index)
if attrNode.name.lower() in ('font', 'font_desc'):
font = attrNode.nodeValue
elif attrNode.name.lower() in ('size', 'font_size'):
if attrNode.nodeValue.isdigit():
attribute['point'] = int(attrNode.nodeValue) / 1024.0
elif attrNode.name.lower() == 'xx-large':
attribute['point'] = 32
elif attrNode.name.lower() == 'x-large':
attribute['point'] = 18
elif attrNode.name.lower() == 'large':
attribute['point'] = 19.2
elif attrNode.name.lower() == 'midium':
attribute['point'] = 16
elif attrNode.name.lower() == 'small':
attribute['point'] = 14.2
elif attrNode.name.lower() == 'x-small':
attribute['point'] = 12
elif attrNode.name.lower() == 'xx-small':
attribute['point'] = 9.6
else:
attribute['size'] = attrNode.nodeValue
elif attrNode.name.lower() in ('foreground', 'fgcolor', 'color'):
color = {'red': 0.0, 'green': 0.0, 'blue': 0.0}
if attrNode.nodeValue.startswith('#'):
match = re.match('^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$',
attrNode.nodeValue)
if match:
color['red'] = int(match.group(1), 16) / 255.0
color['green'] = int(match.group(2), 16) / 255.0
color['blue'] = int(match.group(3), 16) / 255.0
elif re.match('^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$', attrNode.nodeValue):
match = re.match('^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$', attrNode.nodeValue)
color['red'] = int(match.group(1), 16) / 15.0
color['green'] = int(match.group(2), 16) / 15.0
color['blue'] = int(match.group(3), 16) / 15.0
elif attrNode.nodeValue.lower() == 'white':
color['red'] = 1.0
color['green'] = 1.0
color['blue'] = 1.0
elif attrNode.nodeValue.lower() == 'black':
color['red'] = 0.0
color['green'] = 0.0
color['blue'] = 0.0
elif attrNode.nodeValue.lower() == 'gray':
color['red'] = 0.5
color['green'] = 0.5
color['blue'] = 0.5
elif attrNode.nodeValue.lower() == 'red':
color['red'] = 1.0
color['green'] = 0.0
color['blue'] = 0.0
elif attrNode.nodeValue.lower() == 'green':
color['red'] = 0.0
color['green'] = 1.0
color['blue'] = 0.0
elif attrNode.nodeValue.lower() == 'blue':
color['red'] = 0.0
color['green'] = 0.0
color['blue'] = 1.0
elif attrNode.nodeValue.lower() == 'cyan':
color['red'] = 0.0
color['green'] = 1.0
color['blue'] = 1.0
elif attrNode.nodeValue.lower() == 'magenta':
color['red'] = 1.0
color['green'] = 0.0
color['blue'] = 1.0
elif attrNode.nodeValue.lower() == 'yellow':
color['red'] = 1.0
color['green'] = 1.0
color['blue'] = 0.0
attribute['color'] = color
else:
attribute[attrNode.name.lower()] = attrNode.nodeValue.lower()
for child in node.childNodes:
self.parseNode(child, font, bold, italic, attribute)
return
########################################################################
########################################################################
def wordAdd(self, text, font=None, bold=False, italic=False, attribute={}):
########################################################################
if re.search('\\r?\\n', text):
lfCount = len(re.findall('\\r?\\n', text))
restLf = lfCount
for line in re.split('\\r?\\n', text):
self.wordAdd(line, font, bold, italic, attribute)
if restLf > 0:
self.lines.append([])
restLf -= 1
return
########################################################################
if self.lines is None or not isinstance(self.lines, list):
self.lines = [[]]
########################################################################
lineIndex = len(self.lines) - 1
if lineIndex < 0:
self.lines.append([])
lineIndex = 0
elif self.lines[lineIndex] is None or not isinstance(self.lines[lineIndex], list):
self.lines[lineIndex] = []
########################################################################
wordData = {
'font': self.getFontName(font, bold, italic),
'text': self.toUnicode(text)
}
if isinstance(attribute, dict):
for key in attribute.keys():
if key not in wordData.keys():
wordData[key] = attribute[key]
self.lines[lineIndex].append(wordData)
########################################################################
########################################################################
# Preference クラス
#
# GIMP の初期設定ファイルを操作する
#
########################################################################
class GimpPreference:
########################################################################
gimpPreferenceDirPath = None
preferenceDirPath = None
preferenceFilePath = None
########################################################################
config = None
########################################################################
def __init__(self, majorVersion, minorVersion, dirName, fileName):
homePath = os.path.expanduser('~')
gimpPreferenceDirName = '.gimp-' + str(majorVersion) + '.' + str(minorVersion)
self.gimpPreferenceDirPath = os.path.join(homePath, gimpPreferenceDirName)
if not os.path.exists(self.gimpPreferenceDirPath):
return
self.preferenceDirPath = os.path.join(self.gimpPreferenceDirPath, dirName)
if not os.path.exists(self.preferenceDirPath):
os.mkdir(self.preferenceDirPath)
self.preferenceFilePath = os.path.join(self.preferenceDirPath, fileName)
########################################################################
def __del__(self):
pass
########################################################################
def load(self):
if not os.path.exists(self.preferenceFilePath):
return False
self.config = ConfigParser.SafeConfigParser(allow_no_value=True)
try:
self.config.read(self.preferenceFilePath)
return True
except:
return False
########################################################################
def save(self):
if not self.preferenceFilePath:
return False
if not self.config:
return False
try:
with open(self.preferenceFilePath, 'wb') as configfile:
self.config.write(configfile)
return True
except:
return False
########################################################################
def getAll(self, section):
if not section:
return {}
if not self.config:
return {}
try:
results = {}
pairList = self.config.items(section)
for pair in pairList:
results[pair[0]] = pair[1]
return pair
except:
return {}
########################################################################
def getOne(self, section, option, defaultValue=None, isString=False):
if not section:
return defaultValue
if not option:
return defaultValue
if not self.config:
return defaultValue
try:
value = self.config.get(section, option, isString)
if isString:
return value
elif value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
else:
try:
if int(value) == float(value):
return int(value)
else:
return float(value)
except:
return value
except:
return defaultValue
########################################################################
def setOne(self, section, option, value):
if not section:
return False
if not option:
return False
if not self.config:
self.config = ConfigParser.SafeConfigParser(allow_no_value=True)
if not self.config:
return False
if value is None:
value = ''
elif isinstance(value, bool):
if value:
value = '1'
else:
value = '0'
elif not isinstance(value, unicode) and not isinstance(value, str):
value = str(value)
try:
self.config.add_section(section)
except:
pass
try:
self.config.set(section, option, value)
return True
except:
return False
########################################################################
########################################################################
# 縦書クラス情報取得
#
# テキストレイヤーから縦書きレイヤー用の情報を入手するダイアログ
#
########################################################################
class VerticalTextAccess:
########################################################################
(
_LineNumber,
_ColumnNumber,
_RubyTargetNumcer,
_RubyNumber
) = range(4)
########################################################################
image = None
targetTextLayer = None
doPutMessage = True
lastMessage = ''
usableVersion = (2, 8, 0)
canUseLayerGroup = False
pango = None
########################################################################
preferenceDirName = 'VerticalWriting'
preferenceFileName = 'preference.conf'
########################################################################
lineSpaceRate = 1.0
charSpaceRate = 0.0
rubySizeRate = 1.0 / 3.0
rightShiftRate = 0.5
upShiftRate = 0.5
forceSmallerScaleRate = 0.8
########################################################################
useSizeBool = True
useColorBool = True
useRubyBool = True
########################################################################
defaultRotateRightTartget = u'[]{}()<>|-~_|「」『』(){}【】<>《》〔〕〘〙〚〛‥…ー−―〜~'
defaultRightShiftTarget = u'\'"、。’”'
defaultUpShiftTarget = u'、。'
defaultJoinBeforeTarget = u'゜゛'
defaultConsiderOneCharTarget = u'!?'
defaultForceSmallerTarget = u'ぁぃぅぇぉゃゅょっゎァィゥェォヵヶャュョッヮ'
########################################################################
rotateRightTartget = defaultRotateRightTartget
rightShiftTarget = defaultRightShiftTarget
upShiftTarget = defaultUpShiftTarget
joinBeforeTarget = defaultJoinBeforeTarget
considerOneCharTarget = defaultConsiderOneCharTarget
forceSmallerTarget = defaultForceSmallerTarget
flags = {}
########################################################################
def __init__(self, image):
self.results = gtk.RESPONSE_CANCEL
self.image = image
versionLength = len(self.usableVersion)
for index in range(0, versionLength):
if self.usableVersion[index] < gimp.version[index]:
self.canUseLayerGroup = True
break
elif self.usableVersion[index] == gimp.version[index]:
if index == (versionLength - 1):
self.canUseLayerGroup = True
break
continue
else:
self.canUseLayerGroup = False
break
return
########################################################################
def checkUsable(self):
if not self.canUseLayerGroup:
self.errorMessage('GIMP的版本太旧了。')
return False
else:
layer = pdb.gimp_image_get_active_layer(self.image)
if not pdb.gimp_item_is_text_layer(layer):
self.errorMessage('文本图层未被选中。')
return False
else:
return True
########################################################################
# エラーメッセージ機能
#
def errorMessage(self, message=None):
if self.doPutMessage:
if message is None:
message = self.lastMessage
else:
self.lastMessage = message
print message
pdb.gimp_message_set_handler(MESSAGE_BOX)
pdb.gimp_message(message)
# MESSAGE_BOX CONSOLE ERROR_CONSOLE
# gimp.message( message )
return
########################################################################
def getLayerText(self):
if not self.image:
return ''
layer = pdb.gimp_image_get_active_layer(self.image)
if not pdb.gimp_item_is_text_layer(layer):
return ''
self.targetTextLayer = layer
markUp = pdb.gimp_text_layer_get_markup(layer)
if markUp:
self.pango = PangoAccess(markUp)
return self.pango.getAllText()
text = pdb.gimp_text_layer_get_text(layer)
if text:
self.pango = PangoAccess(text)
return text
return ''
########################################################################
def dialogMake(self, proc_name=None, defaultText=None):
self.loadPreference()
self.dialog = gimpui.Dialog(proc_name, "python-fu", None, 0, None, proc_name,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)
)
self.dialog.set_modal(True)
self.dialog.set_alternative_button_order((gtk.RESPONSE_OK, gtk.RESPONSE_CANCEL))
# self.dialog.se_transient()
self.tooltips = gtk.Tooltips()
hBox = gtk.HBox()
label = gtk.Label('行间距(pt):')
hBox.pack_start(label, expand=False)
self.lineSpacePointSpin = gtk.SpinButton()
self.lineSpacePointSpin.set_digits(1)
self.lineSpacePointSpin.set_range(1, 72)
self.lineSpacePointSpin.set_increments(1, 10)
self.setDafultLineSpace()
hBox.pack_start(self.lineSpacePointSpin, expand=False)
self.tooltips.set_tip(self.lineSpacePointSpin, '请指定行之间的间距。')
label = gtk.Label(' 文字间距(pt):')
hBox.pack_start(label, expand=False)
self.charSpacePointSpin = gtk.SpinButton()
self.charSpacePointSpin.set_digits(1)
self.charSpacePointSpin.set_range(0, 72)
self.charSpacePointSpin.set_increments(1, 10)
self.setDafultCharSpace()
hBox.pack_start(self.charSpacePointSpin, expand=False)
self.tooltips.set_tip(self.charSpacePointSpin, '请指定文字之间的间距。')
self.dialog.vbox.pack_start(hBox, expand=False)
label = gtk.Label('')
hBox.pack_start(label, expand=True)
self.resetButton = gtk.Button('重置')
self.resetButton.connect('clicked', self.clickResetButton, None)
hBox.pack_start(self.resetButton, expand=False)
self.tooltips.set_tip(self.resetButton, '重置除ruby项目之外的所有项目。')
self.useSizeCheckButton = gtk.CheckButton('使用单独字体大小信息')
self.useSizeCheckButton.set_active(self.useSizeBool)
self.useSizeCheckButton.show()
self.dialog.vbox.pack_start(self.useSizeCheckButton, expand=False)
self.tooltips.set_tip(self.useSizeCheckButton, '每个字符的大小不同。')
self.useColorCheckButton = gtk.CheckButton('使用单独的字体颜色信息')
self.useColorCheckButton.set_active(self.useColorBool)
self.useColorCheckButton.show()
self.dialog.vbox.pack_start(self.useColorCheckButton, expand=False)
self.tooltips.set_tip(self.useColorCheckButton, '每个字符的颜色不同。')
self.useRubyCheckButton = gtk.CheckButton('使用ruby')
self.useRubyCheckButton.set_active(self.useRubyBool)
self.useRubyCheckButton.show()
self.useRubyCheckButton.connect('toggled', self.tggleUseRubyCheckButton, None)
self.dialog.vbox.pack_start(self.useRubyCheckButton, expand=False)
self.tooltips.set_tip(self.useRubyCheckButton, '请确定是否使用ruby。')
self.rubyVBox = gtk.VBox()
self.rubyVBox.show()
self.rubyHBox = gtk.HBox()
self.rubyHBox.show()
self.rubyHBox.pack_start(self.rubyVBox, expand=True, fill=True, padding=0)
### テキスト表示エリア ###
self.textView = gtk.TextView()
self.textView.set_editable(False)
textBuffer = self.textView.get_buffer()
if defaultText:
textBuffer.set_text(defaultText)
else:
layerText = self.getLayerText()
if layerText:
textBuffer.set_text(layerText)
textBuffer.connect('notify::has-selection', self.notify_has_selection)
textBuffer.connect_after('notify::cursor-position', self.notify_cursor_position)
self.textView.connect('button-release-event', self.button_release_event)
self.textView.connect('button-press-event', self.button_press_event)
# self.textView.connect( 'move-cursor', self.textSelectChange, None )
self.textView.show()
self.tooltips.set_tip(self.textView, '选择想要添加ruby的文字,然后按“添加ruby”按扭。')
self.textScrollArea = gtk.ScrolledWindow()
self.textScrollArea.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.textScrollArea.add(self.textView)
self.textScrollArea.show()
hSeparator = gtk.HSeparator()
hSeparator.show()
# self.dialog.vbox.pack_start( self.textScrollArea )
# self.dialog.vbox.pack_start( hSeparator )
self.rubyVBox.pack_start(self.textScrollArea)
self.rubyVBox.pack_start(hSeparator)
### ルビリストエリア ###
self.rubyListStore = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
self.listBox = gtk.TreeView(self.rubyListStore)
self.listSelection = self.listBox.get_selection()
self.listSelection.connect('changed', self.changedRubySlection, self.listBox)
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn('行数', renderer, text=self._LineNumber)
column.set_sort_column_id(self._LineNumber)
self.listBox.append_column(column)
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn('起始位置', renderer, text=self._ColumnNumber)
column.set_sort_column_id(self._ColumnNumber)
self.listBox.append_column(column)
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn('对象', renderer, text=self._RubyTargetNumcer)
column.set_sort_column_id(self._RubyTargetNumcer)
self.listBox.append_column(column)
renderer = gtk.CellRendererText()
renderer.set_property('editable', True)
renderer.connect('edited', self.rubyChanged, self.rubyListStore, self._RubyNumber)
column = gtk.TreeViewColumn('ruby', renderer, text=self._RubyNumber)
column.set_sort_column_id(self._RubyNumber)
self.listBox.append_column(column)
self.listBox.show()
self.tooltips.set_tip(self.listBox, '如果要更改ruby字符,请双击“对象”并更改它。')
self.rubyScrollArea = gtk.ScrolledWindow()
self.rubyScrollArea.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.rubyScrollArea.add(self.listBox)
self.rubyScrollArea.show()
hBox = gtk.HBox()
hBox.show()
hBox.pack_start(self.rubyScrollArea)
vBox = gtk.VBox()
vBox.show()
self.rubyAddButton = gtk.Button('添加ruby')
self.rubyAddButton.set_sensitive(False)
self.rubyAddButton.connect('clicked', self.clickAddRubyButton, None)
self.rubyAddButton.show()
vBox.pack_start(self.rubyAddButton, expand=False)
self.tooltips.set_tip(self.rubyAddButton, '请从上方区域选择需要添加ruby的文字,然后按下此按扭。')
self.rubyRemoveButton = gtk.Button('删除ruby')
self.rubyRemoveButton.set_sensitive(False)
self.rubyRemoveButton.connect('clicked', self.clickRemoveRubyButton, None)
self.rubyRemoveButton.show()
vBox.pack_start(self.rubyRemoveButton, expand=False)
self.tooltips.set_tip(self.rubyRemoveButton, '请选择左档并按下此按扭。')
hSeparator = gtk.HSeparator()
hSeparator.show()
vBox.pack_start(hSeparator, expand=True)
########################################################################
label = gtk.Label('ruby大小(pt)')
vBox.pack_start(label, expand=False)
self.rubyPointSpin = gtk.SpinButton()
self.rubyPointSpin.set_digits(1)
self.rubyPointSpin.set_range(1, 100)
self.rubyPointSpin.set_increments(1, 10)
self.setDefaultRubySize()
vBox.pack_start(self.rubyPointSpin, expand=False)
self.tooltips.set_tip(self.rubyPointSpin, '请输入ruby字体大小。')
hBox.pack_start(vBox, expand=False)
########################################################################
self.rubyVBox.pack_start(hBox)
self.rubyFrame = gtk.Frame('ruby')
self.rubyFrame.show()
self.rubyFrame.add(self.rubyHBox)
self.dialog.vbox.pack_start(self.rubyFrame, padding=20)
hBox = gtk.HBox()
label = gtk.Label('向右旋转90°的字符')
hBox.pack_start(label, expand=False)
self.rotateRightLineEdit = gtk.Entry()
self.rotateRightLineEdit.set_text(self.rotateRightTartget)
hBox.pack_start(self.rotateRightLineEdit)
self.dialog.vbox.pack_start(hBox)
self.tooltips.set_tip(self.rotateRightLineEdit, '请指定在竖直文本下需要向右旋转90°的字符。')
hBox = gtk.HBox()
label = gtk.Label('向右侧移动的字符')
hBox.pack_start(label, expand=False)
self.rightShiftLineEdit = gtk.Entry()
self.rightShiftLineEdit.set_text(self.rightShiftTarget)
hBox.pack_start(self.rightShiftLineEdit)
self.tooltips.set_tip(self.rightShiftLineEdit, '请指定在竖直文本下需要向右侧移动的字符。')
label = gtk.Label(' 移动比率:')
hBox.pack_start(label, expand=False)
self.rightShiftScaleSpin = gtk.SpinButton()
self.rightShiftScaleSpin.set_digits(2)
self.rightShiftScaleSpin.set_range(0.05, 1)
self.rightShiftScaleSpin.set_increments(0.05, 0.1)
self.rightShiftScaleSpin.set_value(self.rightShiftRate)
hBox.pack_start(self.rightShiftScaleSpin, expand=False)
self.tooltips.set_tip(self.rightShiftScaleSpin, '请指定相对于字符宽度的移动比率。(0~1)')
self.dialog.vbox.pack_start(hBox)
hBox = gtk.HBox()
label = gtk.Label('向上移动的字符')
hBox.pack_start(label, expand=False)
self.upShiftLineEdit = gtk.Entry()
self.upShiftLineEdit.set_text(self.upShiftTarget)
hBox.pack_start(self.upShiftLineEdit)
self.tooltips.set_tip(self.upShiftLineEdit, '请指定在竖直文本下需要向上移动的字符。')
label = gtk.Label(' 移动比率:')
hBox.pack_start(label, expand=False)
self.upShiftScaleSpin = gtk.SpinButton()
self.upShiftScaleSpin.set_digits(2)
self.upShiftScaleSpin.set_range(0.05, 1)
self.upShiftScaleSpin.set_increments(0.05, 0.1)
self.upShiftScaleSpin.set_value(self.upShiftRate)
hBox.pack_start(self.upShiftScaleSpin, expand=False)
self.tooltips.set_tip(self.upShiftScaleSpin, '请指定相对于字符高度的移动比率。(0~1)')
self.dialog.vbox.pack_start(hBox)
hBox = gtk.HBox()
label = gtk.Label('与前一个字符结合的字符')
hBox.pack_start(label, expand=False)
self.joinBeforeLineEdit = gtk.Entry()
self.joinBeforeLineEdit.set_text(self.joinBeforeTarget)
hBox.pack_start(self.joinBeforeLineEdit)
self.dialog.vbox.pack_start(hBox)
self.tooltips.set_tip(self.joinBeforeLineEdit, '请指定您需要与前一个字符结合使用的内容,例如“゛”或“゜”。')
hBox = gtk.HBox()
label = gtk.Label('连续字符被识别为一个字符')
hBox.pack_start(label, expand=False)
self.considerOneCharLineEdit = gtk.Entry()
self.considerOneCharLineEdit.set_text(self.considerOneCharTarget)
hBox.pack_start(self.considerOneCharLineEdit)
self.tooltips.set_tip(self.considerOneCharLineEdit, '请指定在竖直文本下想要识别的连续字符,如“!!?”。')
self.dialog.vbox.pack_start(hBox)
hBox = gtk.HBox()
label = gtk.Label('被强制缩小的字符')
hBox.pack_start(label, expand=False)
self.forceSmallerTargetLineEdit = gtk.Entry()
self.forceSmallerTargetLineEdit.set_text(self.forceSmallerTarget)
hBox.pack_start(self.forceSmallerTargetLineEdit)
self.tooltips.set_tip(self.forceSmallerTargetLineEdit, '请指定在竖直文本下略微缩小的字符,例如“っ”或“ぁ”。')
label = gtk.Label(' 缩小比率:')
hBox.pack_start(label, expand=False)
self.forceSmallerScaleSpin = gtk.SpinButton()
self.forceSmallerScaleSpin.set_digits(2)
self.forceSmallerScaleSpin.set_range(0.05, 1)
self.forceSmallerScaleSpin.set_increments(0.05, 0.1)
self.forceSmallerScaleSpin.set_value(self.forceSmallerScaleRate)
hBox.pack_start(self.forceSmallerScaleSpin, expand=False)
self.tooltips.set_tip(self.forceSmallerScaleSpin, '请指定相对于字符大小的缩小比率。(0~1)')
self.dialog.vbox.pack_start(hBox)
self.dialog.set_default_size(700, 600)
self.dialog.show_all()
########################################################################
def notify_has_selection(self, buffer, *args):
self.textViewSelectionCheck()
########################################################################
def notify_cursor_position(self, buffer, position):
self.textViewSelectionCheck()
########################################################################
def button_release_event(self, textview, event):
self.textViewSelectionCheck()
########################################################################
def button_press_event(self, *args):
self.textViewSelectionCheck()
########################################################################
def textViewSelectionCheck(self):
textbuffer = self.textView.get_buffer()
selection = textbuffer.get_selection_bounds()
if len(selection) < 2:
self.rubyAddButton.set_sensitive(False)
return
else:
text = textbuffer.get_text(selection[0], selection[1], include_hidden_chars=True)
if re.match('^[^\\s]+[\\r]?[\\n].', text):
self.rubyAddButton.set_sensitive(False)
else:
self.rubyAddButton.set_sensitive(True)
########################################################################
def tggleUseRubyCheckButton(self, checkBox, data=None):
if self.useRubyCheckButton.get_active():
self.rubyFrame.show()
else:
self.rubyFrame.hide()
########################################################################
def clickAddRubyButton(self, button, data=None):
########################################################################
textbuffer = self.textView.get_buffer()
selection = textbuffer.get_selection_bounds()
if len(selection) < 2:
return
text = textbuffer.get_text(selection[0], selection[1], include_hidden_chars=True)
if re.match('^[^\\s]+[\\r]?[\\n].', text):
return
########################################################################
lineNo = selection[0].get_line() + 1
columnNo = selection[0].get_line_offset() + 1
self.rubyListStore.append([lineNo, columnNo, text, '请在此输入ruby文本'])
########################################################################
def rubyChanged(self, cellrenderertext, path, new_text, listStore, column):
new_text = new_text.strip()
if new_text:
listStore[path][column] = new_text
########################################################################
def changedRubySlection(self, treeselection, listBox):
if treeselection.count_selected_rows() < 1:
self.rubyRemoveButton.set_sensitive(False)
else:
self.rubyRemoveButton.set_sensitive(True)
########################################################################
def clickRemoveRubyButton(self, button, data=None):
if self.listSelection.count_selected_rows() < 1:
return
########################################################################
selected = self.listSelection.get_selected()
if len(selected) < 2:
return
########################################################################
self.rubyListStore.remove(selected[1])
########################################################################
def clickResetButton(self, button, data=None):
self.resetValues()
self.resetWidgetsValue()
########################################################################
def resetValues(self):
self.lineSpaceRate = 1.0
self.charSpaceRate = 0.0
self.rubySizeRate = 1.0 / 3.0
self.rightShiftRate = 0.5
self.upShiftRate = 0.5
self.forceSmallerScaleRate = 0.8
self.useSizeBool = True
self.useColorBool = True
self.useRubyBool = True
self.rotateRightTartget = self.defaultRotateRightTartget
self.rightShiftTarget = self.defaultRightShiftTarget
self.upShiftTarget = self.defaultUpShiftTarget
self.joinBeforeTarget = self.defaultJoinBeforeTarget
self.considerOneCharTarget = self.defaultConsiderOneCharTarget
self.forceSmallerTarget = self.defaultForceSmallerTarget
########################################################################
def resetWidgetsValue(self):
self.setDafultLineSpace()
self.setDafultCharSpace()
self.useSizeCheckButton.set_active(self.useSizeBool)
self.useColorCheckButton.set_active(self.useColorBool)
self.useRubyCheckButton.set_active(self.useRubyBool)
self.setDefaultRubySize()
self.rotateRightLineEdit.set_text(self.rotateRightTartget)
self.rightShiftLineEdit.set_text(self.rightShiftTarget)
self.rightShiftScaleSpin.set_value(self.rightShiftRate)
self.upShiftLineEdit.set_text(self.upShiftTarget)
self.upShiftScaleSpin.set_value(self.upShiftRate)
self.joinBeforeLineEdit.set_text(self.joinBeforeTarget)
self.considerOneCharLineEdit.set_text(self.considerOneCharTarget)
self.forceSmallerTargetLineEdit.set_text(self.forceSmallerTarget)
self.forceSmallerScaleSpin.set_value(self.forceSmallerScaleRate)
########################################################################
def loadPreference(self):
self.resetValues()
pref = GimpPreference(gimp.version[0], gimp.version[1], self.preferenceDirName, self.preferenceFileName)
if not pref.load():
return
self.lineSpaceRate = float(pref.getOne('space', 'lineSpaceRate', self.lineSpaceRate))
self.charSpaceRate = float(pref.getOne('space', 'charSpaceRate', self.charSpaceRate))
self.useSizeBool = bool(pref.getOne('bool', 'useSizeBool', self.useSizeBool))
self.useColorBool = bool(pref.getOne('bool', 'useColorBool', self.useColorBool))
self.useRubyBool = bool(pref.getOne('bool', 'useRubyBool', self.useRubyBool))
self.rubySizeRate = float(pref.getOne('ruby', 'rubySizeRate', self.rubySizeRate))
self.rightShiftRate = float(pref.getOne('shift', 'rightShiftRate', self.rightShiftRate))
self.upShiftRate = float(pref.getOne('shift', 'upShiftRate', self.upShiftRate))
self.forceSmallerScaleRate = float(pref.getOne('scale', 'forceSmallerScaleRate', self.forceSmallerScaleRate))
dummy = PangoAccess(None)
self.rotateRightTartget = dummy.toUnicode(
pref.getOne('text', 'rotateRightTartget', self.rotateRightTartget, True))
self.rightShiftTarget = dummy.toUnicode(pref.getOne('text', 'rightShiftTarget', self.rightShiftTarget, True))
self.upShiftTarget = dummy.toUnicode(pref.getOne('text', 'upShiftTarget', self.upShiftTarget, True))
self.joinBeforeTarget = dummy.toUnicode(pref.getOne('text', 'joinBeforeTarget', self.joinBeforeTarget, True))
self.considerOneCharTarget = dummy.toUnicode(
pref.getOne('text', 'considerOneCharTarget', self.considerOneCharTarget, True))
self.forceSmallerTarget = dummy.toUnicode(
pref.getOne('text', 'forceSmallerTarget', self.forceSmallerTarget, True))
########################################################################
def savePreference(self):
pointSize = self.getDefaultFontSizeInPoint()
if pointSize <= 0.0:
self.lineSpaceRate = 1.0
self.charSpaceRate = 0.0
self.rubySizeRate = 1.0 / 3.0
else:
self.lineSpaceRate = self.lineSpacePointSpin.get_value() / float(pointSize)
self.charSpaceRate = self.charSpacePointSpin.get_value() / float(pointSize)
self.rubySizeRate = self.rubyPointSpin.get_value() / float(pointSize)
self.rightShiftRate = float(self.rightShiftScaleSpin.get_value())
self.upShiftRate = float(self.upShiftScaleSpin.get_value())
self.forceSmallerScaleRate = float(self.forceSmallerScaleSpin.get_value())
pref = GimpPreference(gimp.version[0], gimp.version[1], self.preferenceDirName, self.preferenceFileName)
if not pref.setOne('space', 'lineSpaceRate', self.lineSpaceRate):
return False
if not pref.setOne('space', 'charSpaceRate', self.charSpaceRate):
return False
if not pref.setOne('bool', 'useSizeBool', self.useSizeBool):
return False
if not pref.setOne('bool', 'useColorBool', self.useColorBool):
return False
if not pref.setOne('bool', 'useRubyBool', self.useRubyBool):
return False
if not pref.setOne('ruby', 'rubySizeRate', self.rubySizeRate):
return False
if not pref.setOne('shift', 'rightShiftRate', self.rightShiftRate):
return False
if not pref.setOne('shift', 'upShiftRate', self.upShiftRate):
return False
if not pref.setOne('scale', 'forceSmallerScaleRate', self.forceSmallerScaleRate):
return False
if not pref.setOne('text', 'rotateRightTartget', self.rotateRightTartget):
return False
if not pref.setOne('text', 'rightShiftTarget', self.rightShiftTarget):
return False
if not pref.setOne('text', 'upShiftTarget', self.upShiftTarget):
return False
if not pref.setOne('text', 'joinBeforeTarget', self.joinBeforeTarget):
return False
if not pref.setOne('text', 'considerOneCharTarget', self.considerOneCharTarget):
return False
if not pref.setOne('text', 'forceSmallerTarget', self.forceSmallerTarget):
return False
return pref.save()
########################################################################
def setDafultLineSpace(self, defaultValue=12):
try:
pointSize = self.getDefaultFontSizeInPoint()
if pointSize < 0:
self.lineSpacePointSpin.set_value(defaultValue)
return
# 行間は文字のポイントサイズで
self.lineSpacePointSpin.set_value(pointSize * self.lineSpaceRate)
except:
return
########################################################################
def setDafultCharSpace(self, defaultValue=0):
try:
pointSize = self.getDefaultFontSizeInPoint()
if pointSize < 0:
self.charSpacePointSpin.set_value(defaultValue)
return
# 文字の間隔はポイントサイズで
self.charSpacePointSpin.set_value(pointSize * self.charSpaceRate)
except:
return
########################################################################
def getDefaultFontSizeInPoint(self):
if not self.image:
return -1.0
try:
layer = pdb.gimp_image_get_active_layer(self.image)
if not pdb.gimp_item_is_text_layer(layer):
return -1.0
sizeInInch = 0
(fontSize, fontUnit) = pdb.gimp_text_layer_get_font_size(layer)
if pdb.gimp_unit_get_identifier(fontUnit).lower() in ['px', 'pix', 'pixel', 'pixels']:
(xResolution, yResoLution) = pdb.gimp_image_get_resolution(self.image)
sizeInInch = fontSize / xResolution
else:
sizeInInch = fontSize / pdb.gimp_unit_get_factor(fontUnit)
point = sizeInInch * 72
return point
except:
return -1.0
########################################################################
def setDefaultRubySize(self, defaultValue=6):
try:
pointSize = self.getDefaultFontSizeInPoint()
if pointSize < 0:
self.rubyPointSpin.set_value(defaultValue)
return
# ルビは 1/3 サイズで
self.rubyPointSpin.set_value(pointSize * self.rubySizeRate)
except:
return
########################################################################
def setResults(self):
self.flags['lineSpacePoint'] = self.lineSpacePointSpin.get_value()
self.flags['charSpacePoint'] = self.charSpacePointSpin.get_value()
self.flags['useFontSize'] = self.useSizeCheckButton.get_active()
self.flags['useFontColor'] = self.useColorCheckButton.get_active()
self.flags['useRuby'] = self.useRubyCheckButton.get_active()
self.flags['rubyPointSize'] = self.rubyPointSpin.get_value()
self.rotateRightTartget = self.pango.toUnicode(self.rotateRightLineEdit.get_text().strip())
self.rightShiftTarget = self.pango.toUnicode(self.rightShiftLineEdit.get_text().strip())
self.rightShiftScale = float(self.rightShiftScaleSpin.get_value())
self.upShiftTarget = self.pango.toUnicode(self.upShiftLineEdit.get_text().strip())
self.upShiftScale = float(self.upShiftScaleSpin.get_value())
self.joinBeforeTarget = self.pango.toUnicode(self.joinBeforeLineEdit.get_text().strip())
self.considerOneCharTarget = self.pango.toUnicode(self.considerOneCharLineEdit.get_text().strip())
self.forceSmallerTarget = self.pango.toUnicode(self.forceSmallerTargetLineEdit.get_text().strip())
self.forceSmallerScale = float(self.forceSmallerScaleSpin.get_value())
self.rubyInfo = []
# 配列としてアクセス
for row in self.rubyListStore:
rowDictionary = {}
rowDictionary['lineNum'] = row[0]
rowDictionary['columnNum'] = row[1]
rowDictionary['targetText'] = self.pango.toUnicode(row[2])
rowDictionary['rubyText'] = self.pango.toUnicode(row[3])
rowDictionary['lineIndex'] = rowDictionary['lineNum'] - 1
rowDictionary['columnIndex'] = rowDictionary['columnNum'] - 1
self.rubyInfo.append(rowDictionary)
self.savePreference()
########################################################################
def run(self):
if self.dialog:
self.results = self.dialog.run()
self.setResults()
self.dialog.destroy()
self.dialog = None
return self.results
else:
return gtk.RESPONSE_CANCEL
########################################################################
########################################################################
# 縦書クラス情報取得
#
# テキストレイヤーから縦書きレイヤーを生成
#
########################################################################
class VerticalTextLayer:
groupNameFormat = '竖排文本组 #'
lineGroupNameFormat = '行 #'
rubyGroupNameFormat = 'Ruby组 #'
########################################################################
def __init__(self, verticalTextAccess):
self.verticalTextAccess = verticalTextAccess
########################################################################
def __del__(self):
pass
########################################################################
def create(self):
if not self.verticalTextAccess:
return
if not self.verticalTextAccess.image:
return
if not self.verticalTextAccess.targetTextLayer:
return
if not self.verticalTextAccess.pango:
return
(fontCount, fontList) = pdb.gimp_fonts_get_list(None)
self.verticalTextAccess.pango.setFontList(fontList)
self.verticalTextAccess.pango.parse()
if not self.verticalTextAccess.pango.lines:
return
if len(self.verticalTextAccess.pango.lines) < 1:
return
self.image = self.verticalTextAccess.image
self.targetTextLayer = self.verticalTextAccess.targetTextLayer
rubyInfo = {}
if self.verticalTextAccess.rubyInfo and len(self.verticalTextAccess.rubyInfo) > 0:
for info in self.verticalTextAccess.rubyInfo:
if 'lineNum' in info.keys():
if info['lineNum'] in rubyInfo.keys():
rubyInfo[info['lineNum']].append(info)
else:
rubyInfo[info['lineNum']] = [info]
self.useRubyFlag = self.verticalTextAccess.flags['useRuby']
self.rubyPointSize = self.verticalTextAccess.flags['rubyPointSize']
pdb.gimp_layer_set_visible(self.targetTextLayer, False)
(xResolution, yResolution) = pdb.gimp_image_get_resolution(self.image)
pointId = 1
unitList = []
for unitId in range(pdb.gimp_unit_get_number_of_units()):
name = pdb.gimp_unit_get_identifier(unitId).lower()
unitList.append(name)
if name in ('pt', 'point', 'points'):
pointId = unitId
(targetLayerOffsetX, targetLayerOffsetY) = pdb.gimp_drawable_offsets(self.targetTextLayer)
targetLayerWidth = pdb.gimp_drawable_width(self.targetTextLayer)
targetLayerHeight = pdb.gimp_drawable_height(self.targetTextLayer)
rightX = targetLayerOffsetX + targetLayerWidth;
topY = targetLayerOffsetY
defaultFont = pdb.gimp_text_layer_get_font(self.targetTextLayer)
(defaultFontSize, defaultFontUnit) = pdb.gimp_text_layer_get_font_size(self.targetTextLayer)
self.verticalTextAccess.pango.setDefaultFont(defaultFont)
self.verticalTextAccess.pango.parse()
self.lines = self.verticalTextAccess.pango.lines
defaultColor = pdb.gimp_text_layer_get_color(self.targetTextLayer)
antialias = pdb.gimp_text_layer_get_antialias(self.targetTextLayer)
(hinting, autoHint) = pdb.gimp_text_layer_get_hinting(self.targetTextLayer)
# '縦書グループ'
index = 0
while pdb.gimp_image_get_layer_by_name(self.image, self.groupNameFormat + str(index)):
index += 1
topLayerGroup = pdb.gimp_layer_group_new(self.image)
pdb.gimp_item_set_name(topLayerGroup, self.groupNameFormat + str(index))
position = pdb.gimp_image_get_layer_position(self.image, self.targetTextLayer)
parent = pdb.gimp_item_get_parent(self.targetTextLayer)
pdb.gimp_image_insert_layer(self.image, topLayerGroup, parent, position + 1)
lineNumber = 0
self.useRubyFlag = self.verticalTextAccess.flags['useRuby']
self.rubyPointSize = self.verticalTextAccess.flags['rubyPointSize']
self.rubyPixcelSize = float(self.rubyPointSize / 72.0) * xResolution
lineSpacePoint = self.verticalTextAccess.flags['lineSpacePoint']
lineSpacePixcel = float(lineSpacePoint / 72.0) * xResolution
charSpacePoint = self.verticalTextAccess.flags['charSpacePoint']
charSpacePixcel = float(charSpacePoint / 72.0) * yResolution
########################################################################
for line in self.lines:
progressVule = float(lineNumber) / float(len(self.lines))
pdb.gimp_progress_update(progressVule)
lineNumber += 1
if not line:
continue
if len(line) < 1:
continue
(count, idList) = pdb.gimp_item_get_children(topLayerGroup)
lineLayerGroup = pdb.gimp_layer_group_new(self.image)
index = 0
while pdb.gimp_image_get_layer_by_name(self.image,
self.lineGroupNameFormat + str(lineNumber) + ' #' + str(index)):
index += 1
pdb.gimp_item_set_name(lineLayerGroup, self.lineGroupNameFormat + str(lineNumber) + ' #' + str(index))
parent = topLayerGroup
pdb.gimp_image_insert_layer(self.image, lineLayerGroup, parent, count)
maxWidth = 0
for word in line:
fontName = defaultFont
fontSize = defaultFontSize
unit = defaultFontUnit
if 'point' in word.keys():
fontSize = float(word['point'])
unit = pointId
if unit == 0:
if fontSize > maxWidth:
maxWidth = fontSize
else:
width = (fontSize / pdb.gimp_unit_get_factor(unit)) * xResolution
if width > maxWidth:
maxWidth = width
offsetY = topY
charsIndex = 0;
########################################################################
for wordIndex in range(len(line)):
word = line[wordIndex]
progressWordVule = float(float(wordIndex) / float(len(line))) / 10.0
pdb.gimp_progress_update(progressVule + progressWordVule)
fontName = defaultFont
fontSize = defaultFontSize
unit = defaultFontUnit
color = defaultColor
# width = fontSize
if 'font' in word.keys():
fontName = word['font']
if 'point' in word.keys() and self.verticalTextAccess.flags['useFontSize']:
fontSize = float(word['point'])
unit = pointId
if 'color' in word.keys() and self.verticalTextAccess.flags['useFontColor']:
color = gimpcolor.RGB(float(word['color']['red']), float(word['color']['green']),
float(word['color']['blue']), 1.0)
fontPixcelSize = fontSize
if unit == 0:
width = fontSize
fontPixcelSize = fontSize
else:
width = (fontSize / pdb.gimp_unit_get_factor(unit)) * xResolution
fontPixcelSize = (fontSize / pdb.gimp_unit_get_factor(unit)) * xResolution
wordTextCheck = word['text']
if wordTextCheck.isspace():
wordTextCheck = 'DummyText'
textFontExtents = pdb.gimp_text_get_extents_fontname(
wordTextCheck,
fontPixcelSize,
PIXELS,
fontName)
textFontWidth = textFontExtents[0]
textFontHeight = textFontExtents[1]
textFontAscent = textFontExtents[2]
textFontDescent = textFontExtents[3]
charsList = []
chaceText = u''
##########################################################################
# 1文字ごとに分解
for oneChar in word['text']:
if self.useRubyFlag and lineNumber in rubyInfo.keys():
# 行に対応するルビの準備
for info in rubyInfo[lineNumber]:
targetText = info['targetText']
rubyText = info['rubyText']
if info['columnIndex'] == charsIndex and len(targetText) > 0 and len(rubyText) > 0:
listIndex = len(charsList)
info['startIndex'] = len(charsList)
joinBeforeTarget = re.escape(self.verticalTextAccess.joinBeforeTarget)
considerOneCharTarget = self.verticalTextAccess.considerOneCharTarget
pattern = u'(.[' + joinBeforeTarget + '])'
pattern += u'|(' + considerOneCharTarget + ']+)'
dummyTarget = re.sub(pattern, u'X', targetText)
info['endIndex'] = info['startIndex'] + len(dummyTarget) - 1
if 'ruby' in word.keys():
word['ruby'][listIndex] = info
else:
word['ruby'] = {listIndex: info}
if oneChar in self.verticalTextAccess.joinBeforeTarget:
# 直前の文字に結合させる文字(濁点など)
if len(chaceText) > 0:
charsList.append(chaceText)
chaceText = u''
index = len(charsList) - 1
if index < 0:
charsList.append(oneChar)
else:
charsList[index] += oneChar
elif oneChar in self.verticalTextAccess.considerOneCharTarget:
# 連続しても1文字と認識させる文字(!? など)
chaceText += oneChar
else:
if len(chaceText) > 0:
charsList.append(chaceText)
chaceText = u''
charsList.append(oneChar)
charsIndex += 1
if len(chaceText) > 0:
charsList.append(chaceText)
chaceText = u''
##########################################################################
ruby = None
for listIndex in range(len(charsList)):
progressCharVule = float(float(listIndex) / float(len(charsList))) / 100.0
pdb.gimp_progress_update(progressVule + progressWordVule + progressCharVule)
oneChar = charsList[listIndex]
if 'ruby' in word.keys() and listIndex in word['ruby'].keys():
# ルビの開始位置設定
ruby = word['ruby'][listIndex]
ruby['top'] = offsetY
ruby['left'] = rightX + (self.rubyPixcelSize / 2.0)
fontSizeRate = 1.0
feedSizePoint = fontSize * fontSizeRate
feedSizePixcel = feedSizePoint
if unit == 0:
feedSizePixcel = feedSizePoint
else:
feedSizePixcel = (feedSizePoint / pdb.gimp_unit_get_factor(unit)) * yResolution
if oneChar in self.verticalTextAccess.forceSmallerTarget:
fontSizeRate = self.verticalTextAccess.forceSmallerScale
if oneChar.isspace():
offsetY += (feedSizePixcel * fontSizeRate) + charSpacePixcel
continue
layer = pdb.gimp_text_layer_new(self.image, oneChar, fontName, fontSize * fontSizeRate, unit)
index = 0
while pdb.gimp_image_get_layer_by_name(self.image, oneChar + ' #' + str(index)):
index += 1
width = pdb.gimp_drawable_width(layer)
if width > maxWidth:
width = maxWidth
offsetX = rightX - maxWidth + ((maxWidth - width) / 2.0)
pdb.gimp_item_set_name(layer, oneChar + ' #' + str(index))
pdb.gimp_layer_set_offsets(layer, offsetX, offsetY)
(count, idList) = pdb.gimp_item_get_children(lineLayerGroup)
pdb.gimp_image_insert_layer(self.image, layer, lineLayerGroup, count)
pdb.gimp_text_layer_set_color(layer, color)
pdb.gimp_text_layer_set_antialias(layer, antialias)
pdb.gimp_text_layer_set_hinting(layer, hinting, autoHint)
pdb.gimp_text_layer_set_hint_style(layer, TEXT_HINT_STYLE_FULL)
if oneChar in self.verticalTextAccess.rotateRightTartget:
centerX = float(offsetX) + (pdb.gimp_drawable_width(layer) / 2.0)
centerY = float(offsetY) + (pdb.gimp_drawable_height(layer) / 2.0)
pdb.gimp_item_transform_rotate_simple(layer, ROTATE_90, False, centerX, centerY)
if oneChar in self.verticalTextAccess.rightShiftTarget or oneChar in self.verticalTextAccess.upShiftTarget:
newOffsetX = offsetX
newOffsetY = offsetY
if oneChar in self.verticalTextAccess.rightShiftTarget:
newOffsetX += pdb.gimp_drawable_width(layer) * self.verticalTextAccess.rightShiftScale
if oneChar in self.verticalTextAccess.upShiftTarget:
newOffsetY -= pdb.gimp_drawable_height(layer) * self.verticalTextAccess.upShiftScale
pdb.gimp_layer_set_offsets(layer, int(newOffsetX), int(newOffsetY))
########################################################################
# 次の文字の開始位置
nextOffsetY = offsetY + (feedSizePixcel * fontSizeRate) + charSpacePixcel
########################################################################
if ruby and ruby['endIndex'] <= listIndex and len(ruby['rubyText']) > 0:
# ルビの埋め込み
rubyGroup = pdb.gimp_layer_group_new(self.image)
index = 0
while True:
rubyGroupName = self.rubyGroupNameFormat + str(index)
if not pdb.gimp_image_get_layer_by_name(self.image, rubyGroupName):
break
index += 1
pdb.gimp_item_set_name(rubyGroup, rubyGroupName)
(count, idList) = pdb.gimp_item_get_children(lineLayerGroup)
pdb.gimp_image_insert_layer(self.image, rubyGroup, lineLayerGroup, count)
rubyFontExtents = pdb.gimp_text_get_extents_fontname(
ruby['rubyText'],
self.rubyPixcelSize,
PIXELS,
defaultFont)
rubyFontWidth = rubyFontExtents[0]
rubyFontHeight = rubyFontExtents[1]
rubyFontAscent = rubyFontExtents[2]
rubyFontDescent = rubyFontExtents[3]
rubyTop = ruby['top'] + math.ceil(textFontDescent * (-1) * fontSizeRate / 2.0)
rubyLeft = ruby['left']
rubyBottom = nextOffsetY - charSpacePixcel
rubyCharCount = len(ruby['rubyText'])
restRubyPixcel = (rubyBottom - rubyTop) - (rubyFontHeight * rubyCharCount)
rubyFeed = 0
if restRubyPixcel > 0:
rubyFeed = restRubyPixcel / (rubyCharCount + 1)
rubyTop += rubyFeed
########################################################################
for rubyChar in ruby['rubyText']:
if rubyChar.isspace():
rubyTop += self.rubyPixcelSize + rubyFeed
rubyLayer = pdb.gimp_text_layer_new(self.image, rubyChar, defaultFont, self.rubyPointSize,
pointId)
index = 0
while True:
rubyName = rubyChar + ' #' + str(index)
if not pdb.gimp_image_get_layer_by_name(self.image, rubyName):
break
index += 1
pdb.gimp_item_set_name(rubyLayer, rubyName)
pdb.gimp_layer_set_offsets(rubyLayer, rubyLeft, rubyTop)
(count, idList) = pdb.gimp_item_get_children(rubyGroup)
pdb.gimp_image_insert_layer(self.image, rubyLayer, rubyGroup, count)
pdb.gimp_text_layer_set_hinting(rubyLayer, True, True)
pdb.gimp_text_layer_set_hint_style(rubyLayer, TEXT_HINT_STYLE_FULL)
rubyTop += pdb.gimp_drawable_height(rubyLayer) + rubyFeed
########################################################################
ruby = None
########################################################################
# 開始位置を次の行へ
offsetY = nextOffsetY
########################################################################
########################################################################
rightX -= maxWidth + lineSpacePixcel
########################################################################
pdb.gimp_image_set_active_layer(self.image, topLayerGroup)
pdb.gimp_progress_update(1.0)
########################################################################
########################################################################
# テキストレイヤーから縦書きレイヤーを作成する
#
def python_fu_vertical_writing_2_8(image, drawable):
proc_name = 'python-fu-vertical-writing-2-8'
verticalWriting = VerticalTextAccess(image)
if not verticalWriting.checkUsable():
# 使用不可
return
# 縦書き処理を実行
verticalWriting.dialogMake(proc_name)
results = verticalWriting.run()
if results == gtk.RESPONSE_CANCEL:
return
layerCreator = VerticalTextLayer(verticalWriting)
pdb.gimp_image_undo_group_start(image)
pdb.gimp_progress_init(u'「縦書き写植」を処理中です...', None)
try:
layerCreator.create()
except:
pdb.gimp_message('処理中にエラーが発生しました。')
pdb.gimp_progress_end()
pdb.gimp_image_undo_group_end(image)
return
########################################################################
register(
'python-fu-vertical-writing-2-8', # プロシジャの名前
'テキストレイヤーから縦書きレイヤーを作成する。',
# プロシジャの説明文
'文本竖写脚本,根据文本图层创建竖排文本图层,适用于GIMP 2.8版以上。',
# PDBに登録する追加情報
'かんら・から', # 作者名
'GPLv3', # ライセンス情報
'2013.08.30', # 作成日
'文本竖书(Python)', # メニューアイテム
'*', # 対応する画像タイプ
[
(PF_IMAGE, 'image', 'Input image', None),
(PF_DRAWABLE, 'drawable', 'Input drawable', None)
], # プロシジャの引数
[], # 戻り値の定義
python_fu_vertical_writing_2_8, # 処理を受け持つ関数名
menu='/Layer/图层操作(Python-fu)' # メニュー表示場所
)
main() # プラグインを駆動させるための関数