前言:在开发程序时,可能需要将一张照片或影像显示在程序内部界面上。一般来说,界面的大小是固定的,不超过屏幕大小,但是我们需要显示的照片往往有不同的分辨率,并且一张照片的像素动不动就上千万,即使1920*1080的屏幕最多也只能显示200万像素的照片。要想在程序界面上浏览整张图像,必然需要加入缩放和平移功能。缩放使得我们能够以较原图更低的分辨率加载并显示整张图像,平移使得在较大分辨率尺度下界面只能加载影像部分区域时方面我们浏览影像的其他部分。参考目前已有的各类图像浏览软件,提出一种实现方案。

简介:采用平面坐标系统一图像坐标和显示窗口(界面)坐标。当图像加载时,界面与图像计算缩放比例,界面上每个像素按照缩放比例生成坐标位置,然后根据坐标位置对原图进行采样并生成一张与界面大小完全一样的影像,之后界面直接显示该图像即可。完成图像加载后,界面上显示的是原图根据窗口大小按比例缩放后的全貌。接下来,只需要改变缩放比例即可实现缩放,增大缩放比例相当于界面无形中增大了尺寸,原图看起来在界面中变得更小,而减小缩放比例,相当于界面变小了,界面只能框下原图更小范围。平移则是通过改变界面中心坐标实现,由于加载图像时,界面中心坐标初始值与图像中心坐标一致,当改变界面中心坐标,通过界面中心坐标和窗口大小从带坐标的原图中进行采样即可获取平移后的影像。

接下来对上述方案进行详细描述。

第一步:读取图像,获取图像的宽和高以及色彩信息,其实图像本身就是一个二维平面坐标系统,(0,0)对应一个RGB色彩值,(0,1)又对应另一个RGB色彩值。如果想要获取某一区域的像素数据,只需要根据这个坐标值加上需要获取的宽度和高度参数即可,图像裁剪也是同样原理。那么现在就可以根据图像宽和高建立一个坐标系,以图像左下角为坐标系原点。图像中心坐标为image_center=(image_width/2,image_height/2)。此时还有一个重要步骤就是设定步长,也就是每个像素在坐标系中的跨度范围,由于已经将图像中心坐标设定为(image_width/2,image_height/2),那么一个像素跨度为1,image_step=1。此时原始图像已经有了固定的坐标,它的每个像素在坐标系中的位置就固定了,坐标系中有图像的位置就有了对应的RGB值,图像范围以外的位置可以设定为黑色或其他颜色对应的RGB值。

概念图:

android 平移动画平移x轴 平移界面_android 平移动画平移x轴

第二步:将在界面中全局显示图像。首先获取界面宽和高,window_width,window_height。接下来,计算缩放比例:width_scale=window_width/image_width,height_scale=window_height/image_height。由于要保持图像宽高比,必须比较width_scale和height_scale,选取较小的一个作为缩放比例scale。接着计算界面上每个像素在全局显示下对应的步长,window_step=image_step/scale。由于图像全局显示,界面的中心和图像中心一致,即window_center=image_center。接下来根据界面已经确定的参数(window_width,window_height,window_step,window_center),从坐标系中寻找界面每个像素对应的RGB值。由于界面宽高比和图像宽高比不保证一致,图像全局加载后肯定是存在一些空白的地方。

概念图:

android 平移动画平移x轴 平移界面_加载_02

实际效果:

android 平移动画平移x轴 平移界面_android 平移动画平移x轴_03

第三步:放大和缩小。有前面两步的实现,已经为放大缩小打好了基础。第二步为了在界面全局显示图像,相当于已经进行了一次缩放。图像上每一个像素的坐标都是固定的,界面中心坐标与图像中心坐标一致,我们只需要改变界面上每个像素在坐标系中的步长即可。当window_step值增加,也就是整个界面在坐标系中范围增大,界面边界随着window_step增大将远远超出图像范围,图像在界面中占的面积也就变小,也就实现了将图像缩小显示,随着不断缩小,最终图像只会在界面中占一个像素。反之,window_step值减小,整个界面在坐标系中范围也就减小,界面边界将小于图像范围,显示的将是图像的部分区域,随着不断放大,界面最终只会显示图像中某一个像素的RGB值。

缩小操作概念图:

android 平移动画平移x轴 平移界面_缩放_04

缩小效果:

android 平移动画平移x轴 平移界面_加载_05

放大操作概念图:

android 平移动画平移x轴 平移界面_缩放_06

放大效果图:

android 平移动画平移x轴 平移界面_缩放_07

第四步:平移的实现。其实将图像和界面统一在一个坐标系内本身就是为了同时解决缩放和平移问题的。本质上讲,缩放并没有对图像进行任何缩小或放大操作,是界面投影到坐标系中的大小在发生变化。界面在坐标系中的投影大小可以解决图像缩放问题,那么界面中心在坐标系中的投影位置也就解决了图像的平移问题。当我们改变window_center,不改变window_step,由于界面的宽和高是固定的,整个界面在坐标系中进行移动,那么获取到的图像就是移动图像产生的效果。

平移操作概念图:

android 平移动画平移x轴 平移界面_加载_08

移动效果图:

android 平移动画平移x轴 平移界面_android 平移动画平移x轴_09

总结:到此为止,图像浏览界面的缩放和平移实现就完成了。该方案的核心思想就是给原图每一个像素赋予一个固定坐标,在界面中进行缩放和平移,变化的是界面在坐标系中投影的位置和大小,图像本身是没有进行任何操作的。通过调整界面大小和位置,从坐标系中去采样色彩信息,返回一张图像,由于界面的像素是固定的,每次采样只采样与界面分辨率一样的数据量,计算量相对较小,基本可以实时更新画面。如果界面窗口大小是1000*1000像素,那么总像素是100万,每次缩放或平移操作需要更新100万像素的数据量,如果电脑配置较差,可能会有些许卡顿。

补充:利用鼠标来实现图像的缩放和平移。一般图像浏览软件都会加入鼠标事件监听来实现图像的缩放和平移。这里我采用鼠标滚轮来实现图像缩放,鼠标左键拖动来实现图像平移。可以定义当滚轮向前滚动来放大图像,滚轮每向前滚动一个单位,window_step/1.1,由于我们是缩放界面在坐标系中的大小,不是缩放图像,当界面的步长减小,对应在坐标系中的大小也就是变小,能够采样到的图像范围也就变小,实现了图像的放大,与图像放大是反的,因为图像本身没有变化。当然,如果想要缩小图像显示,加大界面步长,window_step*1.1,那么采样到的图像范围就更大,图像在界面中是缩小了的。这里的1.1作为缩放参数是可以更改的。图像的平移采用鼠标左键拖动,当按下鼠标左键,记录下当前鼠标在界面上的位置,这个位置包含两个参数X和Y,当鼠标开始拖动,获取每次拖动后的位置,减去上一次的位置,结合界面当前步长window_step和XY方向上的平移量便获得了界面中心坐标在坐标系中需要移动的位置,再根据这个位置重新采样图像并更新到界面上。