PyCairo:如何调整图像大小并将其中心旋转到最终画布

问题描述

使用PyCairo,我希望有一种方法可以在上下文中放置,调整给定ImageSurface的大小并旋转它,但是可以旋转图像中心(而不是左上角

好的,我尝试了在这里找到的示例,但是没有成功。 让我们详细介绍“上下文”。

我有一个“ finale” ImageSurface(例如A),上面写有一些其他图像和文本。 我想在指定位置上放置另一个ImageSurface(例如B),该位置是将B放在A上的左上角。然后我需要调整B的大小(减小其大小)并旋转它 ,而不是其左上角

以下是所需结果的说明:

enter image description here

我尝试了以下方法,但没有成功:

    def draw_rotated_image(ctx,image_surface,left,top,width,height,angle):
        ctx.save()
        w = image_surface.get_width()
        h = image_surface.get_height()
        cl = left / (width/w)
        ct = top  / (height/h)
        ctx.rotate(angle*3.1415927/180)
        ctx.scale(width/w,height/h)
        ctx.translate(cl + (-0.5*w),ct + (-0.5*h) )
        ctx.set_source_surface(image_surface,0)
        ctx.paint()

        ctx.restore()
        return

非常感谢您的帮助:)

解决方法

好吧,我终于做到了! (感谢我的14岁儿子让我修改了三角函数)

我试图在这里解释我的解决方案。 首先,我不是数学家。因此,可能是最好的方法,当然我的解释肯定有错误,但是我只是在解释我用来获得良好结果的逻辑方法。

最好的方法是首先在矩形周围绘制一个圆,因为我们需要根据所需的角度围绕该矩形的圆移动该矩形的左上角。 因此,要获取矩形圆的半径,我们需要计算其假设,然后除以2:

hypothenuse = math.hypot(layerWidth,layerHeight)
radius = hypothenuse / 2

然后我们将能够在矩形周围绘制一个圆。

第二,我们需要知道在该圆上哪个角度是矩形的实际左上角。 因此,我们需要计算矩形的反正切值,即arc-tan(height / width)。 但是因为我们想知道距0°的距离是多少度,所以我们需要计算相反的arc-tan(width / height)。

最后,另一个奇点是开罗0°实际上是90°,因此我们将不得不再次旋转。

可以通过以下简单图形显示: enter image description here

那么,最后,需要了解什么? 如果要以某个角度绘制一个图层,并以其中心旋转,则左上角的点将根据所需角度在圆周围移动。 给定角度为0的左上角位置必须为“参考”。

因此,我们需要获得新的X-Y位置,在该位置开始放置图层以使其能够旋转: enter image description here

现在,我们可以编写一个函数,该函数将返回左上角矩形的X-Y pos,以给定角度绘制该矩形:

def getTopLeftForRectangleAtAngle(layerLeft,layerTop,layerWidth,layerHeight,angleInDegrees):
    # now we need to know the angle of the top-left corner
    # for that,we need to compute the arc tangent of the triangle-rectangle:
    layerAngleRad = math.atan((layerWidth / layerHeight))
    layerAngle = math.degrees(layerAngleRad)

    # 0° is 3 o'clock. So we need to rotate left to 90° first
    # Then we want that 0° will be the top left corner which is "layerAngle" far from 0
    if (angleInDegrees >= (90 + layerAngle)):
        angleInDegrees -= (90 + layerAngle)
    else:
        angleInDegrees = 360 - ((90 + layerAngle) - angleInDegrees)
    
    angle = (angleInDegrees * math.pi / 180.0)

    centerLeft = layerLeft + (layerWidth / 2)
    centerTop  = layerTop  + (layerHeight / 2)

    # hypothenuse will help us knowing the circle radius
    hypothenuse = math.hypot(layerWidth,layerHeight)
    radius = hypothenuse / 2

    pointX = centerLeft + radius * math.cos(angle)
    pointY = centerTop  + radius * math.sin(angle)

    return (pointX,pointY)

最后,这是如何与我们要调整大小,旋转并在上下文上书写的图像一起使用它:

def getTopLeftForRectangleAtAngle(layerLeft,pointY)