【问题标题】:How to properly do centered zooming?如何正确进行居中缩放?
【发布时间】:2021-05-01 14:27:39
【问题描述】:

我的问题比编程更通用,但是涉及到一些基本的C代码,希望不要在这里结束。

我有一个圆形的目标显示器,它将显示一个图像,首先居中并拟合:

圆的半径是 360,这是固定的。

我需要添加放大和缩小功能(以防图像大于目标)。在这个例子中,上面的图像是1282x720,所以它远高于圆圈的大小。 (为了适应圈子,现在大致是313x176

我想做一个正确对齐的“中心固定缩放”,即:当前居中的任何内容都应在缩放操作后保持居中。

图像被放入名为 scroller 的组件中,该组件具有设置其 偏移量 的选项,即从其内容的顶部和左侧跳过多少像素。默认情况下,此滚动组件将其内容对齐到左上角。

我在图片中间放了一个红点,以便于观察。

所以在放大时会发生这种情况(图像开始左对齐):

请注意它仍然在垂直的中间,因为它的高度仍然比它的容器小。

但是在下一个放大步骤中,红色中心点会稍微向下,因为在这种情况下,图像的高度比容器高,因此它也开始顶部对齐:

现在,让它始终保持在中心很容易:

我需要让滚动条滚动到

image_width/2 - 180, //horizontal skip
image_height/2 - 180 //vertical skip

在这种情况下,如果我从适合尺寸放大到完整尺寸的 5 步,滚动条的跳过数字是:

Step0 (fit): 0, 0 
Step1: 73, 0
Step2: 170, 16
Step3: 267, 71
Step4: 364, 125
Step5 (original size): 461, 180

但我不希望图像始终保持在中心,我宁愿做一些类似于图像编辑器正在做的事情,即:在缩放操作期间中心点应保持在中心,而不是用户可以平移和下一次缩放操作将使新的中心点保持在中心。

我该怎么做?

目标语言是 C,并且没有可用的额外 3rd 方库,我需要手动完成。

Scroller 实际上是一个elm_scroller

【问题讨论】:

  • 我认为这是一个非常有趣的问题,但不幸的是,如果没有一些关于您正在编程的语言的上下文,我认为它有点模糊。例如,C# WPF 将这个煮沸的做法变得非常简单ScaleTransform,您可以在其中告诉它比例因子并定义一个中心点(例如 X=50%,Y=50%)。如您所述,Python 可能需要一些 3rd 方成像库和一些手动代码。对于经验不足的程序员来说,C 语言显然更具挑战性,因为它甚至需要实现一些基本概念,比如中心点的概念等。
  • 语言是C,我补充一下。而且没有可用的库,只能手动计算。
  • 您能否也发布一个scroller 是什么的示例或模型?您是否有能力更改该控件的代码?这很可能会改变人们提供答案和反馈的方式。
  • Scroller 实际上是一个elm_scroller,基本上它只是一个容器,它可以随内容扩展并通过滚动条使其“可滚动”。
  • 这个好像不太好。让我们只考虑宽度:在原始情况下居中:1282 是宽度,461 是偏移量。小一号:1088 宽度和364 偏移量。计算比例:1088/1282 ~ 0.8487。新偏移量的计算:0.8487*461 ~ 391。而不是 364。

标签: c zooming


【解决方案1】:

您需要修改所有四个位置点,不仅是 x2 和 y2,将它们视为矩形的边,因此要保持居中缩放,正方形的每一边都需要“增长”到绝对中心图片。

  • X1 > 左,Y1 > 上
  • X2 > 右 , Y2 > 下
#include <stdint.h>
#include <stdio.h>

typedef struct {

    int32_t x;
    int32_t y;
    int32_t width;
    int32_t heigth;

    uint32_t o_width;
    uint32_t o_heigth;

} IMG_C_POS;

void set_img_c_pos(IMG_C_POS * co, int32_t w, int32_t h){
    co->o_heigth = h;
    co->o_width = w;
    co->heigth = h;
    co->width = w;
    co->x = 0;
    co->y = 0;
}

void add_img_zoom(IMG_C_POS * co, uint16_t zoom){
    uint32_t zoom_y = (co->o_heigth / 100) * (zoom / 2);
    uint32_t zoom_x = (co->o_width / 100) * (zoom / 2);
    co->heigth -= zoom_y;
    co->width -= zoom_x;
    co->x += zoom_x;
    co->y += zoom_y;
}

void sub_img_zoom(IMG_C_POS * co, uint16_t zoom){
    uint32_t zoom_y = (co->o_heigth / 100) * (zoom / 2);
    uint32_t zoom_x = (co->o_width / 100) * (zoom / 2);
    co->heigth += zoom_y;
    co->width += zoom_x;
    co->x -= zoom_x;
    co->y -= zoom_y;
}

void img_new_center(IMG_C_POS * co, int16_t nx, int16_t ny){
    int32_t oy = co->o_heigth / 2;
    if(oy <= ny){
        co->heigth += oy - ny;
        co->y += oy - ny;
    } else {
        co->heigth -= oy - ny;
        co->y -= oy - ny;
    }
    int32_t ox = co->o_width / 2;
    if(ox <= nx){
        co->width += ox - nx;
        co->x += ox - nx;
    } else {
        co->width -= ox - nx;
        co->x -= ox - nx;
    }
}

void offset_img_center(IMG_C_POS * co, int16_t x_offset, int16_t y_offset){
    if (y_offset != 0){
        int32_t y_m_size = (co->o_heigth / 100) * y_offset;
        co->heigth += y_m_size;
        co->y += y_m_size;
    }
    if (x_offset != 0){
        int32_t x_m_size = (co->o_width / 100) * x_offset;
        co->width += x_m_size;
        co->x += x_m_size;
    }
}


int main(void) {
    
    IMG_C_POS position;
    set_img_c_pos(&position, 1282, 720);

    sub_img_zoom(&position, 50);
    img_new_center(&position, (1282 / 2) - 300, (720 / 2) + 100);

    for (int i = 0; i < 4; i++){
        printf("X1 -> %-5i Y1 -> %-5i X2 -> %-5i Y2 -> %-5i \n", 
        position.x, position.y, position.width, position.heigth
        );

        offset_img_center(&position, 4, -2);
        add_img_zoom(&position, 20);
    }
    
    return 0;
}

【讨论】:

  • 谢谢。一个小的补充:我的图像的原始尺寸是 1282x720,为了使这个图像适合所需的圆圈,我必须缩小。它不是精确的 20%,因为它取决于图像的纵横比。所以我需要从缩小的图像开始适合圆圈。然后我想有5个步骤达到原始大小并保持中心。但是,如果用户平移图像,我还想保留中心(当前的中心,而不是红点!),这个解决方案是否也能做到这一点?
  • 是的,要移动中心,您只需要添加或删除到 de 轴(x1 和 x2 或 y1 和 y2),我添加了 2 个额外的功能来移动中心,您可以更改% 到 px,如果你愿意,也可以。我使用的数字是为了测试它是否有效,您需要找出适合您的方法和女巫价值观。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-21
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多