Okay, so let me explain how this works. You hook it up to Ten Scripts and can execute it via a shortcut.
When run, it will open up a window asking you to input font name, font size, line width and line height. These are global values for the entire thing. (It is possible to make it none global but that would be more work and I think it would be better spent on the Lazy Text Tool)
You write the text like normal, from left to right, but the output will be how you want it, vertical and right to left.
To edit, text, you have to select it with the Select Shapes Tool
Note: You want to change the Font name in this script defaultFont = 'Open Sans Extrabold' to whatever font you want to use as default (like the japanese font)
Important: This script plays around with the clipboard tricks, aka, it backs up your clipboard, then uses copy and paste for editing internally. So normally it isn’t a problem, just try not to have a million record excel file in the clipboard or something while using.
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import re
import time
def openWindow():
defaultFont = 'Open Sans Extrabold'
defaultFontSize = 10.0
defaultLineWidth = 100
defaultLineHeight = 100
defaultTransform = ''
w = QDialog()
layout = QVBoxLayout(w)
fontCmb = QFontComboBox()
layout.addWidget(fontCmb)
hlayout = QHBoxLayout()
fontSize = QDoubleSpinBox()
hlayout.addWidget(QLabel("Font Size:"))
hlayout.addWidget(fontSize)
widthSize = QDoubleSpinBox()
widthSize.setMaximum(200)
hlayout.addWidget(QLabel("Line Width:"))
hlayout.addWidget(widthSize)
heightSize = QDoubleSpinBox()
heightSize.setMaximum(200)
hlayout.addWidget(QLabel("Line Height:"))
hlayout.addWidget(heightSize)
layout.addLayout(hlayout)
textBox = QPlainTextEdit()
layout.addWidget(textBox)
hlayout2 = QHBoxLayout()
button1 = QPushButton("Add Text")
button1.clicked.connect(w.accept)
hlayout2.addWidget(button1)
editContent = readSvgContent()
#print (editContent)
if editContent is not None:
match = re.compile('^.*?\<text.*?id="(vf_.*?)".*$', re.DOTALL).search(editContent)
if match:
matchData = match.group(1).split('_')
defaultLineWidth = float(matchData[1])
defaultLineHeight = float(matchData[2])
matchTransform = re.compile('^.*?\<text.*?transform="(.*?)".*$', re.DOTALL).search(editContent)
if matchTransform: defaultTransform = matchTransform.group(1)
matchFont = re.compile('^.*?\<text.*?font-family="(.*?)".*$', re.DOTALL).search(editContent)
if matchFont: defaultFont = matchFont.group(1)
matchFontSize = re.compile('^.*?\<text.*?font-size="(\d+)".*$', re.DOTALL).search(editContent)
if matchFontSize: defaultFontSize = float(matchFontSize.group(1))
editContent = editContent.replace('<tspan>','<p>')
#print (editContent)
textBox.document().setHtml(editContent)
button1.setText("Edit Text")
else:
editContent = None
button2 = QPushButton("Cancel")
button2.clicked.connect(w.reject)
hlayout2.addWidget(button2)
layout.addLayout(hlayout2)
def changeFont():
font = textBox.document().defaultFont()
font.setFamily(fontCmb.currentFont().family())
textBox.document().setDefaultFont(font)
textBox.setPlainText(textBox.toPlainText())
fontCmb.currentFontChanged.connect(changeFont)
def changeFontSize():
font = textBox.document().defaultFont()
font.setPointSizeF(fontSize.value())
textBox.document().setDefaultFont(font)
textBox.setPlainText(textBox.toPlainText())
fontSize.valueChanged.connect(changeFontSize)
fontCmb.setCurrentFont(QFont(defaultFont))
changeFont()
fontSize.setValue(defaultFontSize)
changeFontSize()
widthSize.setValue(defaultLineWidth)
heightSize.setValue(defaultLineHeight)
w.show()
if w.exec_() == 0: return
lines = textBox.toPlainText().split("\n")
fontWidth = 0
hPos = 0
pretty = "\n"
blockCount = textBox.document().blockCount()
iblock = textBox.document().begin()
output = '<text '
output += 'id="vf_'+ str(widthSize.value()) +'_'+ str(heightSize.value()) +'_'+str(time.time())+'" '
output += 'transform = "'+defaultTransform+'" '
output += 'font-family="'+fontCmb.currentFont().family()+'" '
output += 'font-size="'+str(fontSize.value())+'">' + pretty
while iblock != textBox.document().end():
blockText = list(iblock.text())
blockLineCount = iblock.layout().lineCount()
fontHeight = 0
output += '<tspan y="0">' + pretty
for i in range(blockLineCount):
line = iblock.layout().lineAt(i)
for i2 in range(line.textLength()):
glyph = line.glyphRuns(line.textStart()+i2, 1)[0]
if fontWidth == 0:
rawFont = glyph.rawFont()
fontWidth = rawFont.averageCharWidth()*2
hPos = (blockCount * fontWidth * widthSize.value()) / 100
r = glyph.boundingRect()
output += '<tspan dy="'+str( (fontHeight*heightSize.value())/100 )+'" x="'+str(hPos + (( (fontWidth-r.width()/2) * widthSize.value())/100) )+'">'+blockText[i2]+'</tspan>' + pretty
fontHeight = r.height()
iblock = iblock.next()
hPos -= (fontWidth * widthSize.value()) / 100
output += '</tspan>' + pretty
output += '</text>' + pretty
doc = Krita.instance().activeDocument()
svgWidth = str( (doc.width()/72)*doc.resolution() )
svgHeight = str( (doc.height()/72)*doc.resolution() )
svgContent = '''<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Created using Krita: https://krita.org -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:krita="http://krita.org/namespaces/svg/krita"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
width="''' + svgWidth + '''pt"
height="''' + svgHeight + '''pt"
viewBox="0 0 ''' + svgWidth + ' ' + svgHeight + '''">
<defs/>''' + output + "</svg>"
#print( svgContent )
writeSvgContent(svgContent, doc.activeNode(), (editContent is not None) )
def writeSvgContent(svgContent, layer, editMode):
mimeOldContent=QGuiApplication.clipboard().mimeData();
mimeStoreContent=QMimeData()
for mimeType in mimeOldContent.formats():
mimeStoreContent.setData(mimeType,QByteArray(mimeOldContent.data(mimeType)))
if editMode: Krita.instance().action('edit_cut').trigger()
mimeNewContent=QMimeData()
mimeNewContent.setData('image/svg', svgContent.encode())
QGuiApplication.clipboard().setMimeData(mimeNewContent)
Krita.instance().action('edit_paste').trigger()
QGuiApplication.clipboard().setMimeData(mimeStoreContent)
return None
def readSvgContent():
returnContent = None
node = Krita.instance().activeDocument().activeNode()
if node.type() != 'vectorlayer': return None
mimeOldContent=QGuiApplication.clipboard().mimeData();
mimeStoreContent=QMimeData()
for mimeType in mimeOldContent.formats():
mimeStoreContent.setData(mimeType,QByteArray(mimeOldContent.data(mimeType)))
Krita.instance().action('edit_copy').trigger()
mimeContent=QGuiApplication.clipboard().mimeData();
for mimeType in mimeContent.formats():
if mimeType.startswith('image/svg'):
returnContent = str( QByteArray(mimeContent.data(mimeType)) , 'utf-8')
break
QGuiApplication.clipboard().setMimeData(mimeStoreContent)
return returnContent
openWindow()
Now question is, should I add it to ShapesAndLayers plugin ![]()
Well, yes and no. The current SVG system does not support SVG2 so it isn’t convenient, but it is possible and pretty cleanly through utilizing the tspans y, x and dy properties. I even made them all in order so technically the current text tool can add support with little programming.
But it would definitely be nice to get a better fully functioning on canvas text tool.
