c - 如何正确进行居中缩放?
问题描述
我的问题比编程更通用,但是它涉及一些基本的 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,并且没有其他可用的第三方库,我需要手动执行此操作。
Scroller 实际上是一个elm_scroller。
解决方案
您需要修改所有四个位置点,不仅是 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;
}