第一次尝试旋转和缩放位图时,我做了一个显而易见的选择:从源矩阵中取出每个像素,通过旋转和缩放对其进行变换,然后将值写入目标中变换后的位置。结果如下所示:
bitmap = J( bmy = 200, bmx = 300, RGB Color( 1, 1, 1 ) );//white
scale = 3;
tranmat = (1 || 0 || 80) |/ (0 || 1 || 10) |/ (0 || 0 || 1); // 2D translation matrix
scalmat = (scale || 0 || 0) |/ (0 || scale || 0) |/ (0 || 0 || 1); // 2D scale matrix
angle = 33 * Pi() / 180;
sangle = Sin( angle );
cangle = Cos( angle );
rotamat = (cangle || -sangle || 0) |/ (sangle || cangle || 0) |/ (0 || 0 || 1); // 2D rotation matrix
forward = (tranmat * scalmat * rotamat)`; // transpose here
// make a sample image
testimage = Text Box( "matrix", <<SETWRAP></SETWRAP>
Transformed text has holes转换后的文本有漏洞
看起来很糟糕。 正确的方法是使用变换矩阵的逆矩阵并询问“对于目标位图中的每个像素,我应该使用源中的哪个像素?” 但答案几乎总是落在四个像素之间。 一个合理的答案是使用四个像素的加权平均值,更复杂的答案可能看起来像双三次插值。 此代码使用加权平均值:
// this bitmap is used to build the image. drawtext will write
// each string into this bitmap.
bitmap = J( bmy = 300, bmx = 580, RGB Color( 1, 1, 1 ) );//white
// drawtext is a slow routine that draws a text string into a buffer,
// then samples that buffer to create a rotated, scaled copy in the
// bitmap buffer.
drawtext = Function(
{x = 0, y = 0, txt = "hello", degAngle = 0, xjust = 0, yjust = 1, fontsize = 99, scale = .5, textcolor = RGB Color( 0, 0, 0 )}, // parms
{// locals, initialized. Creates a transform matrix and its inverse
t = Text Box( txt, <<SETWRAP></SETWRAP>
Sampling the source image with linear interpolation使用线性插值对源图像进行采样
代码的后半部分与其说是关于矩阵变换,不如说是制作一幅有趣的图画。 水平条纹是通过将多个图像副本混合在一起创建的,每个副本移动一个像素,并保留较少的更远的移动。
Big, tilted, orange大,倾斜,橙色