IOS下,利用捏合手势实现图像缩放和显示

图像的缩放查看,在移动终端上早已不是问题,任何一个人都能够熟练的操作图像的缩放。本文所讲述的重点并不是应用层面上的,而是从编码的角度去自己实现一个图像的缩放应用。作者(就是我自己)最近在做一款APP,其中有一个功能就是抓取PC桌面的图像发送到手机上显示。虽说现在的手机屏幕在慢慢的变大,已经可以达到5.5英寸,但是相比PC显示器的20+英寸,还是显得很小,可以展现的内容也很有限。如果整个PC屏幕显示在手机屏幕上,可以自行脑补一下,你能够看清上面的文字和图片么?那么问题来了,整个功能就需要实现对抓取PC桌面的放大和缩小显示。下面我将比较详细接用代码写出使用捏合手势来实现的缩放功能。


        首先我们需要两个参数来保存重要的信息:

CGFloat m_fScale;  // 缩放倍数
CGPoint m_ptStart; // 显示图像块的起始点

m_fScale这个参数很容易理解,你缩放图像,一定得有个缩放倍数,那么就是它了;至于m_ptStart这个参数,我想我可能需要稍微啰嗦两句,来解释一下:当你放大图像时,由于显示区域时固定的,那么你就不可能把整个放大的图像都显示出来,你只能显示某一个块图像,那么这一块图像需要有一个起始点。

好吧,我承认,以上的解释是废话,我们还是来举个例子来说明一下吧。

比如,你的图像是1920 x 1080的分辨率,你放大了2倍,那么整个图像的分辨率就会变成3840 x 2160;如果你把3840 x 2160的图像直接显示出来,那你看到的结果是非但没有放大的效果,还缩小了。因为可显示区域大小是固定的,分辨率越大,显示内容越小。那么如何才能显示放大的图像呢?这时m_ptStart这个参数的作用就显现出来了。假设这个参数的值为(0,0),那么就是说从图像的标准坐标原点开始显示,显示的长度宽度也是固定的(假设是1920 x 1080),那么针对于3840 x 2160这个放大的图像,从(0,0)点开始显示长宽为1920 x 1080的图像块,这样显示的图像就是放大了(因为原本在固定可显示区域要显示1920 x 1080的图像,现在只要显示960 x 540的图像块就可以了)。

这样的例子,不知道是不是所有人都能够理解,还不理解,我也表示无能为力了。


        其次,我们需要给一个UIView添加捏合手势识别,假设这个UIView就是我们要在上面显示图像的View,这段代码的作用是,将一个捏合手势添加的View上,并且关联了捏合手势的处理函数gesturePinch。

// m_pTouchView已经关联到了UIView空间上
m_pTouchView.multipleTouchEnabled = YES;  // 允许UIView多点触控
UIPinchGestureRecognizer *recongnizerPinch = [[UIPinchGestureRecognizer alloc]init];
[recongnizerPinch addTarget:self action:@select(gesturePinch:)];
[m_pTouchView addGestureRecognizer:recognizerPinch];

这是捏合手势的处理函数,对缩放倍数进行边界检查,并且设置缩放倍数。

-(void)gestruePinch:(id)sender {
    UIPinchGestureRecognizer *gesture = (UIPinchGestureRecognizer*)sender;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
         // 记录捏合手势开始时的缩放系数
         m_fStartScale = m_fScale;
    }
    
    // 捏合手势默认的系数是1.0
    // 当识别为放大手势时,系数会从1.0开始递加; 当识别为缩小手势时,系数会从1.0开始递减,直到为0.0
    CGFloat scale = gesture.scale + m_fStartScale - 1.0;
    
   // 锁定缩放倍数,缩放倍数只能在1.0~3.0之间
    if (scale - 1.0 < 0.000001)
    {
        scale = 1.0;
    }
    else if (scale - 3.0 > 0.000001)
    {
        scale  = 3.0;
    }

    m_fScale = scale;
}


好了,到此为止,所有准备工作都做完了,下面该最关键的部分登场了——抠图并放大。

-(void)captureImage:(UIImage*)org scale:(CGFloat)scale startPoint:(CGPoint)startPoint {
    // 如果缩放倍数为1.0的话,表示不需要进行缩放处理
    if (scale - 1.0 <= 0.000001)
    {
        return org;
    }

    // 根据缩放倍数计算需要显示的图像的宽度和高度
    int nW = org.size.width  / scale;
    int nH  = org.size.height / scale;
   // 根据startPoint和新的宽度高度,调整新的显示起始点。
    int nX = (org.size.width - startPoint.x) >= nW ? startPoint.x : (org.size.width - nW);
    int nY = (org.size.height - startPoint.y) >= nH ? startPoint.y : (org.size.height - nH);

    // 提取指定rect的图像块
    CGImage subImageRef = CGImageCreateWidthImageInRect(org.CGImage, CGRectMake(nX, nY, nW, nH);
    UIImage     *capImg = [UIImage imageWidthCGImage:subImageRef];
    CGImageRelease(subImageRef);


    // 针对提取出来的图像块,将它还原到可现实区域大小,以实现放大的效果
    UIGraphicsBeginImageContext(org.size);
    [capImg drawInRect:CGRectMake(0, 0, org.size.width, org.size.height)];
    UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return retImage;
}

图像处理完毕了,剩下的就是将图像画到UIView上就行了。

-(void)drawImage:(UIImage*)img {
    if (img == nil)
    {
        return ;
    }

    m_pTouchView.layer.contents = (id)[self captureImage:img scale:m_fScale startPoint:m_ptStart].CGImage;
}

你发现了什么?有问题?有参数没介绍?

对,你答对了,m_pStart这个显示起始坐标还没有设置,我们一直假设的是原始坐标(0,0);

至于这个坐标,你可以再touchesBegan,touchesMoved和touchesEnded这些函数中处理一下,就可以得到坐标了,这里就不写出具体代码了,留给细心的读者作为课后作业吧。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值