美文网首页
截屏:Image的scale参数:UIImagePNGRepre

截屏:Image的scale参数:UIImagePNGRepre

作者: 金风细细 | 来源:发表于2016-12-13 10:57 被阅读1218次

一. 原因

今天做项目遇到这样一个问题,困扰了一阵,最后请教了一位同事才解决的:

    CGSize imageSize = CGSizeZero;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (UIInterfaceOrientationIsPortrait(orientation))
        imageSize = [UIScreen mainScreen].bounds.size;
    else
        imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
    
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, window.center.x, window.center.y);
        CGContextConcatCTM(context, window.transform);
        CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
        if (orientation == UIInterfaceOrientationLandscapeLeft)
        {
            CGContextRotateCTM(context, M_PI_2);
            CGContextTranslateCTM(context, 0, -imageSize.width);
        }
        else if (orientation == UIInterfaceOrientationLandscapeRight)
        {
            CGContextRotateCTM(context, -M_PI_2);
            CGContextTranslateCTM(context, -imageSize.height, 0);
        } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
            CGContextRotateCTM(context, M_PI);
            CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
        }
        if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
        {
            [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
        }
        else
        {
            [window.layer renderInContext:context];
        }
        CGContextRestoreGState(context);
    }
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    NSData * data = UIImagePNGRepresentation(image);
    //UIImage * png= [UIImage imageWithData:data];
    UIImage * png = [[UIImage alloc] initWithData:data scale:image.scale];
    return png;

这个函数是截屏的代码,复制粘贴即可使用

问题在于最后几句:
当得到了一个image后,在执行完UIImagePNGRepresentation对它进行png的转换后,使用 [UIImage imageWithData:data];我发现得到的png的size居然翻倍了.也就是说:

图1-1

image的scale为:{375,667} 转为png后居然成了{750,1334}, 不能忍啊

原因是什么呢?UIImagePNGRepresentation函数是没有问题的.我在再次由它得到UIImage时,需要设置scale属性为源image的scale,也就是2,两者要保持一致.
因为[UIImage imageWithData:data];的scale默认是1,所以用这个函数就会出现不预期的效果,要用 initWithData:scale这个函数

二. scale学习

看到这里,感觉scale还是蛮重要的一个属性,之前图片用的粗浅,也没怎么关注
scale的描述为:image的扩大倍数.

  1. 如果一张图片名字包含:....@2x 则这张图片的scale属性默认就被设置为了2.其他的图片都是默认的scale,为1
  2. image的size属性(它是逻辑尺寸),乘以scale属性,就是这个图片实际的像素值.
    所以像上面的例子中:

所以理解一下:

一开始我画出来的image,像素为{750,1334 }
PNG转出来的imagedata. 像素还是{750,1334 }.
我在initWithData:scale:中设置它的scale,则它的size就是:像素/scale.
所以如果原图image的像素是{750,1334 },scale设置为2,则png的size是{375,667};如果我把scale设置为1,则png的size是{750,1334}.而默认的scale是1,所以这就弄清楚了为什么我使用UIImagePNGRepresentation对原图进行png的转换后,size会扩大一倍的原因.

三. 画图学习

好了,进一步研究下我的原图像素在哪里设置.实话说这段截屏代码是参考的网上的,自己大略看了下.现在仔细看一下

1. UIGraphicsBeginImageContextWithOptions(size,opaque,scale)

这个函数创建一个基于位图(像素)的画图context,并把它push进图形context的栈.

1.1 它使用view采用的坐标,即左上角为原点,向下和右延伸,scale参数作用在所画的图上,会把位图的scale属性标记为这个值.如果传0.0,则这个参数会用设备的scale,像我的iphone6s是2 所以我UIGraphicsBeginImageContextWithOptions那里传入scale为0,结果出来的图scale是2的.

1.2 size是传入的逻辑size

1.3 文档告诉我们,和该参数配套使用的有:
获取图片:UIGraphicsGetImageFromCurrentImageContext
用完后要出栈:必须用UIGraphicsEndImageContext,而不是UIGraphicsPopContext
获取这个栈中的context:UIGraphicsGetCurrentContext
1.4 还有UIGraphicsBeginImageContext,参数都用默认的

2. UIGraphicsGetCurrentContext

一般当前的图形context都是nil或者默认值.

2.1 对于一个UIView来说,在进入它的drawRect: 方法之前,系统会自动给它的图形context栈push一个context.我们直接用UIGraphicsGetCurrentContext获取就是了

2.2 那不是在UIView中画图的时候怎么办呢?我们要手动的调用UIGraphicsPushContext方法或者1中的UIGraphicsBeginImageContextWithOptions,给栈中push一个context,再用这个方法取出来用.

3. CGContextSaveGState

把当前context的statecopy一份,存入context的state栈
每个context都维护了一个自己的栈,存放state,state是啥东西?有点多:


图2-1

好吧,后面几个函数意思没能领会住,果断复习layer的知识去了,搞清楚了回来补充.

4. renderInContext

把调用者的层画到context中,层是view展示的样子,这个方法即把view画到了context中

5. UIGraphicsGetImageFromCurrentImageContext

从当前context中取出图片
这个函数,必须是和基于位图的context一起使用,也就是context需要是UIGraphicsBeginImageContext函数创建的,不然返回nil

6. UIGraphicsEndImageContext

将基于位图的context弹出栈.它必须和UIGraphicsBeginImageContext配对使用

所以基于上面6个函数的思想,还有比较简单的截屏办法
这是我的参考

四. 检测截屏

这个向通知中心注册一个通知就好了

 [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(userDidTakeScreenshot:)
                                                 name:UIApplicationUserDidTakeScreenshotNotification object:nil];

响应函数:

-(void) userDidTakeScreenshot:(NSNotification* )notification{

好了,暂时告一段落,我去复习下layer和画图的知识

相关文章

  • 截屏:Image的scale参数:UIImagePNGRepre

    一. 原因 今天做项目遇到这样一个问题,困扰了一阵,最后请教了一位同事才解决的: 这个函数是截屏的代码,复制粘贴即...

  • Android 5.0 截屏 Image image = ima

    Image image = imageReader.acquireNextImage();截屏时这句话报空指针(为...

  • UIImage镜像翻转

    [UIImage imageWithCGImage:image.CGImage scale:image.scale...

  • uipath保存截屏异常

    用Take screenshot 和 Save image抓取屏幕,截屏: 运行后,抓取的截屏,一半是黑的 解决方...

  • 开机启动跳转

    防止先出现第一页再跳:截屏,将截屏的image放置在window的最前边 UIGraphicsBeginImage...

  • 搜狗截屏

    安装搜狗截屏插件 1.打开搜狗工具箱 右键搜狗输入法-工具箱image.png2.安装截屏插件 点工具箱-截屏(口...

  • UIImage

    UIImage的size,scale属性 图像的尺寸由 image.size * image.scale 决定 U...

  • App退出前台的模糊效果

    思路: 1、将要推出到后台,截屏image 2、给image添加模糊效果 3、退出后台后,在window上显示模糊...

  • 四月份论文列表

    2019.4.5Attention to Scale: Scale-aware Semantic Image Se...

  • 2019-02-22-搜狗截图-Markdown标的语言

    搜狗截图配置 下载安装搜狗输入法 下载截屏image.png 打开设置image.png 设置快捷键image.p...

网友评论

      本文标题:截屏:Image的scale参数:UIImagePNGRepre

      本文链接:https://www.haomeiwen.com/subject/qpommttx.html