PyCairo:如何调整大小将图像的中心旋转到最终的画布 [英] PyCairo : how to resize & rotate an image by its center to a final canvas

查看:55
本文介绍了PyCairo:如何调整大小将图像的中心旋转到最终的画布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using PyCairo, I want to be able to have a method that can put, resize & rotate a given ImageSurface on a context, but rotating by the center of the image (not the top-left)

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

Okay I've tried the examples I've found here but without any success. Let's introduce the "context" in details.

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

I've got a "finale" ImageSurface (say A) on which some other images & texts are written. I want to put on it another ImageSurface (say B), at a specified position where this position is the top-left where to put B on A. Then I need to resize B (reduce its size) and to rotate it by its center instead of by its top-left corner.

以下是所需结果的说明:

Here is an illustration of the wanted result :

我尝试了以下操作,但没有成功:

I've tried the following but without success:

    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, 0)
        ctx.paint()

        ctx.restore()
        return

非常感谢您的帮助:)

推荐答案

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

Well, I finally made it ! (thanks to my 14 year old son who made me revise my trigonometry)

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

I'm trying to explain here my solution. First, I AM NOT A MATHEMATICIAN. So there is probably a best way, and surely my explanation have errors, but I'm just explaining the logical way I have used to get the good result.

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

The best idea for that is to first draw a circle around the rectangle, because we need to move the top-left corner of this rectangle, around its own circle, according to the desired angle. So to get the radius of the rectangle circle, we need to compute its hypothenuse, then to divide by 2 :

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

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

Then we will be able to draw a circle around the rectangle.

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

Second, we need to know at which angle, on this circle, is the actual top-left corner of the rectangle. So for that, we need compute the invert tangent of the rectangle, which is arc-tan(height/width). But because we want to know how many degrees are we far from 0°, we need to compute the opposite so arc-tan(width/height).

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

Finally, another singularity is that Cairo 0° is in fact at 90°, so we will have to rotate again.

这可以通过以下简单图形显示:

This can be shown by this simple graphic :

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

So finally, what is necessary to understand ? If you want to draw a layer, with an angle, rotated by its center, the top-left point will move around the circle according to the desired angle. The top-left position with a given angle of 0 needs to be "the reference".

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

So we need to get the new X-Y position where to start putting the layer to be able to rotate it :

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

Now, we can write a function that will return the X-Y pos of the top left rectangle where to draw it with a given angle :

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)

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

And finally, here is how to use it with an image we want to resize, rotate and write on a context:

def draw_rotated_image(ctx, image_surface, left, top, width, height, angle=0.0, alpha=1.0):
    ctx.save()
    w = image_surface.get_width()
    h = image_surface.get_height()

    # get the new top-left position according to the given angle
    newTopLeft = getTopLeftForRectangleAtAngle(left, top, width, height, angle)

    # translate
    ctx.translate(newTopLeft[0], newTopLeft[1])
    # rotate
    ctx.rotate(angle * math.pi / 180)
    # scale & write
    ctx.scale(width/w, height/h)
    ctx.set_source_surface(image_surface, 0, 0)
    ctx.paint_with_alpha(alpha)

    ctx.restore()
    return

这篇关于PyCairo:如何调整大小将图像的中心旋转到最终的画布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆