我们正在尝试使用html5和canvas创建文字艺术,如下面的图像,但我们找不到合适的参数来创建这种设计。
text art design parameters
text art design
这种文字艺术需要其他参数吗?
提前致谢
最佳答案
由于我喜欢绘画,因此我实现了您的问题的两种概念文字艺术。
即使您似乎不再关心,它也适合有好奇心的人使用。
基本原理
为了达到上述效果,您需要利用一种本质上是2D texture mapping的技术,尽管该技术大大简化了,但我们要保持左右边缘的笔直。
从本质上讲,它包括将正方形转换为其他形状1
蓝色方块代表绘制有文字的图像,红色方块代表应如何“变形”最终图像。
通过选择适当的变形,您可以实现不同类型的对象。
特殊情况
通常,纹理映射需要在要映射的形状上添加一些tessellation 2,并且可能需要使用Barycentric coordinate system。
但是,在本例中,我们可以做出强假设,即我们将一个矩形映射到一个新的(凸的)形状,该形状具有与原始宽度相同的宽度,并且不会更改垂直边缘。
简而言之,我们没有进行这种转换。
这很重要,因为我们可以使用简单的算法来实现转换。
转换算法
基本上,我们将原始矩形切成垂直条纹,并根据与条纹高度相对应的新形状缩放每个条纹。
例如,在上面的示例映射中,中间“条带”的高度如何变化:
HTML5 Canvas允许我们使用方法drawImage
重绘条纹(实际上是像素列),方法为drawImage(source, x, 0, 1, h, x, upperY, 1, lowerY-upperY)
。
这将采用与x处的条纹相对应的矩形,并在相同的x处但以不同的y并以不同的高度绘制它。
有时我们可能需要将一个比整个画布短的矩形作为源,但是过程是相同的。
upperY和lowerY可以作为x的函数进行计算,并且可以取任何值。仔细选择生成这些值的函数将获得所需的效果。
1. For X = 0 To Canvas.Width
1.1 upperY = f_upper(x);
1.2 lowerY = f_lower(x);
1.3 Canvas.DrawImage(SrcCanvs, x, 0, 1, SrcCanvs.Height, x, upperY, 1, lowerY-upperY);
第一艺术
关于实施
小提琴是here。
首先,第一件事是:我们不绘制整个画布,而是对其子矩形进行评估,该子矩形的高度足以覆盖文本并与画布一样大。
要参数化此矩形,我们只需要其高度和距画布顶部的垂直距离即可。
这两个参数是“文字高度”和“文字顶部间隙”。
地图是
其余的操作非常简单:我们为用户提供了选择,以点的高度设置文本树对点之间的距离,以“文本高度”为单位,以“画布”宽度为单位,设置“红色”对的水平位置。
上层函数是常数函数0。
下函数是分段函数:当x在中点之前时使用前半部分,否则使用后半部分。
对于这两种情况,我们只计算较低点之间的线:上半部为绿色-红色,下半部为红色-蓝色。
第二艺术
关于实施
小提琴是here。
我们让用户选择顶部和底部波的振幅(以文本高度分为单位)和频率(以波纹数为单位),以及两个波周期的缩放参数(以Canvas宽度分为单位)。
我无法快速在InkScape上绘制贴图,因此让我想像到了。
基本上,我们使用sin作为具有不同参数的上,下函数。
通过适当地改变波浪参数,所有四种文字艺术都可以通过。
第二艺术片段
/// (c) Ken Fyrstenberg Nilsen, Abidas Software .com
/// License: CC-Attribute
var ctx = demo.getContext('2d'),
font = '64px impact',
w = demo.width,
h = demo.height,
os = document.createElement('canvas'),
octx = os.getContext('2d');
os.width = w;
os.height = h;
octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
function renderArtText()
{
var ta = parseInt(iTa.value, 10);
var tp = parseInt(iTp.value, 10);
var ba = parseInt(iBa.value, 10);
var bp = parseInt(iBp.value, 10);
var yo = parseInt(iYo.value, 10);
var ww = parseInt(iWw.value, 10);
var th = parseInt(iTh.value, 10);
var to = parseInt(iTo.value, 10);
vTa.innerHTML = ta;
vTp.innerHTML = tp;
vBa.innerHTML = ba;
vBp.innerHTML = bp;
vYo.innerHTML = yo;
vWw.innerHTML = ww;
vTh.innerHTML = th;
vTo.innerHTML = to;
octx.clearRect(0, 0, w, h);
ctx.clearRect(0, 0, w, h);
octx.fillText(iText.value.toUpperCase(), w * 0.5, 0);
var l = w*ww/100;
ta = ta*th/100;
ba = ba*th/100;
for (var x = 0; x < w; x++)
{
var s, f;
s = ta*Math.sin(2*Math.PI*x/l * tp);
f = ba*Math.sin(2*Math.PI*x/l * bp);
ctx.drawImage
(
os,
x, to, 1, th,
x, yo-s, 1, th-f+s
);
}
}
iTa.onchange = iTp.onchange = iBa.onchange = iWw.onchange =
iBp.onchange = iText.onkeyup = iYo.onchange =
iTh.onchange = iTo.onchange = renderArtText;
renderArtText();
span {
display:inline-block;
width:120px;
text-align:right;
font:12px sans-serif;
}
<canvas id=demo width=400 height=300></canvas>
<br>
<span>Top wave height:</span>
<input id="iTa" type="range" min=-100 max=100 value=0>
<span id="vTa">0</span>
<br>
<span>Top wave ripples:</span>
<input id="iTp" type="range" min=1 max=3 value=1>
<span id="vTp">1</span>
<br>
<span>Bottom wave height:</span>
<input id="iBa" type="range" min=-100 max=100 value=50>
<span id="vBa">50</span>
<br>
<span>Bottom wave ripples:</span>
<input id="iBp" type="range" min=1 max=3 value=1>
<span id="vBp">1</span>
<br>
<span>Waves width:</span>
<input id="iWw" type="range" min=20 max=100 value=80>
<span id="vWw">80</span>
<br>
<span>Offset Y:</span>
<input id="iYo" type="range" min=0 max=100 value=30>
<span id="vYo">30</span>
<br>
<span>Text height:</span>
<input id="iTh" type="range" min=10 max=100 value=60>
<span id="vTh">60</span>
<br>
<span>Text top gap:</span>
<input id="iTo" type="range" min=0 max=30 value=12>
<span id="vTo">12</span>
<br>
<span>Text:</span>
<input id="iText" type="text" value="BRIDGE TEXT">
第一个艺术片段
/// (c) Ken Fyrstenberg Nilsen, Abidas Software .com
/// License: CC-Attribute
var ctx = demo.getContext('2d'),
font = '64px impact',
w = demo.width,
h = demo.height,
os = document.createElement('canvas'),
octx = os.getContext('2d');
os.width = w;
os.height = h;
octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';
function renderArtText()
{
var hs = parseInt(iHs.value, 10);
var hm = parseInt(iHm.value, 10);
var hf = parseInt(iHf.value, 10);
var xm = parseInt(iXm.value, 10);
var yo = parseInt(iYo.value, 10);
var th = parseInt(iTh.value, 10);
var to = parseInt(iTo.value, 10);
vHs.innerHTML = hs;
vHm.innerHTML = hm;
vHf.innerHTML = hf;
vXm.innerHTML = xm;
vYo.innerHTML = yo;
vTh.innerHTML = th;
vTo.innerHTML = to;
octx.clearRect(0, 0, w, h);
ctx.clearRect(0, 0, w, h);
octx.fillText(iText.value.toUpperCase(), w * 0.5, 0);
var ysl = (th + hs*th/100)/2;
var yml = (th + hm*th/100)/2;
var yfl = (th + hf*th/100)/2;
var xs = 0;
xm = xm*w/100;
var xf = w;
yo = yo*h/100;
for (var x = 0; x < w; x++)
{
var f;
if (x < xm)
f = ysl + x*(yml-ysl)/(xm-xs);
else
f = yml + (x-xm)*(yfl-yml)/(xf-xm);
ctx.drawImage
(
os,
x, to, 1, th,
x, yo, 1, f
);
}
}
iHs.onchange = iHm.onchange = iHf.onchange =
iXm.onchange = iText.onkeyup = iYo.onchange =
iTo.onchange = iTh.onchange = renderArtText;
renderArtText();
span {
display:inline-block;
width:90px;
text-align:right;
font:12px sans-serif;
}
<canvas id=demo width=400 height=300></canvas>
<br>
<span>Start Height:</span>
<input id="iHs" type="range" min=0 max=200 value=10>
<span id="vHs">10</span>
<br>
<span>Middle Height:</span>
<input id="iHm" type="range" min=0 max=200 value=167>
<span id="vHm">167</span>
<br>
<span>End Height:</span>
<input id="iHf" type="range" min=0 max=200 value=30>
<span id="vHf">30</span>
<br>
<span>Middle point:</span>
<input id="iXm" type="range" min=0 max=100 value=50>
<span id="vXm">50</span>
<br>
<span>Offset Y:</span>
<input id="iYo" type="range" min=0 max=100 value=30>
<span id="vYo">30</span>
<br>
<span>Text height:</span>
<input id="iTh" type="range" min=10 max=100 value=60>
<span id="vTh">60</span>
<br>
<span>Text top gap:</span>
<input id="iTo" type="range" min=0 max=30 value=13>
<span id="vTo">13</span>
<br>
<span>Text:</span>
<input id="iText" type="text" value="TEXT ART">
1仍然具有笔直的侧边缘。
2仅在这种情况下为二维。