【问题标题】:Saving UIView contents in iOS 4 with real size of the images inside (i.e. scale contentes up for save)在 iOS 4 中使用内部图像的实际大小保存 UIView 内容(即放大内容以进行保存)
【发布时间】:2011-05-11 22:36:46
【问题描述】:

我有一个 UIView,其中有许多 UIImageViews 作为子视图。该应用程序在 iOS4 上运行,我使用具有视网膜显示分辨率的图像(即图像以 scale = 2 加载)

我想保存 UIView 的内容......但是......里面有图像的真实大小。 IE。视图的大小为 200x200,内部的图像比例为 2,我想保存 400x400 的结果图像和所有图像的真实大小。

现在首先想到的是创建一个新的图像上下文并再次加载其中 scale=1 的所有图像,这应该可以,但我想知道是否有更优雅的方法可以做到这一点?似乎需要大量的内存和处理器时间来重新加载所有内容,因为它已经完成了......

附言如果有人有答案 - 包括代码会很好

【问题讨论】:

    标签: iphone uiview ios4 calayer retina-display


    【解决方案1】:

    难道你不能只创建一个所需大小的新图形上下文,使用 CGAffineTransform 将其缩小,渲染根 UIView 的根层,将上下文恢复为原始大小并渲染图像吗?还没有为视网膜内容尝试过这个,但这似乎适用于在 UIImageViews 中按比例缩小的大图像......

    类似:

    CGSize originalSize = myOriginalImage.size; //or whatever
    
    //create context
    UIGraphicsBeginImageContext(originalSize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context); //1 original context
    
    // translate/flip the graphics context (for transforming from CG* coords to UI* coords
    CGContextTranslateCTM(context, 0, originalSize.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    
    //original image
    CGContextDrawImage(context, CGRectMake(0,0,originalSize.width,originalSize.height), myOriginalImage.CGImage);
    
    CGContextRestoreGState(context);//1 restore to original for UIView render;
    
    //scaling
    CGFloat wratio = originalSize.width/self.view.frame.size.width;
    CGFloat hratio = originalSize.height/self.view.frame.size.height;
    
    //scale context to match view size
    CGContextSaveGState(context); //1 pre-scaled size
    CGContextScaleCTM(context, wratio, hratio);
    
    //render 
    [self.view.layer renderInContext:context];
    
    CGContextRestoreGState(context);//1  restore to pre-scaled size;
    
    UIImage *exportImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    【讨论】:

    • 嗨史蒂文,如果我错了,请纠正我,但实际上不是按比例缩小渲染(即使用像素图像数据的 1/4)而不是按比例放大或核心图形以不同的方式工作?
    • 我在这里可能是错的,因为我对 Quartz 这部分的细节有点模糊,但上面的测试表明它不是按比例缩小的渲染。起初,我专门创建了一个按比例缩小的位图上下文,重新缩放并使用位图上下文进行渲染,但结果很糟糕(如您所料)。但是,只要原始来源的大小/质量合理,上述方法就可以提供清晰的图像。
    • 作为后记,上面的代码假定 myOriginalImage 大于 UIView 点大小(视网膜或其他)
    • 我自己也不是 CG 王……不过我会试试你的解决方案,如果它真的不按比例缩小的话,真的很有趣
    【解决方案2】:

    我已经将 MKMapView 中的图钉保存为 PNG 文件(在视网膜显示中):MKPinAnnotationView: Are there more than three colors available?

    以下是使用其视网膜定义执行保存UIView (theView) 的关键部分的摘录:

    
    -(void) saveMyView:(UIView*)theView {
        //The image where the view content is going to be saved.
        UIImage* image = nil;
        UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, 2.0);
        [theView.layer renderInContext: UIGraphicsGetCurrentContext()];
        image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        NSData* imgData = UIImagePNGRepresentation(image);
        NSString* targetPath = [NSString stringWithFormat:@"%@/%@", [self writablePath], @"thisismyview.png" ];
        [imgData writeToFile:targetPath atomically:YES]; 
    }
    
    

    -(NSString*) writablePath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; return documentsDirectory; }

    【讨论】:

    • 嘿 +1 提到 UIGraphicsBeginImageContextWithOptions ......天哪,每次小的 iOS 更新都会出现大量新的随机函数......我累了 :)
    • UIGraphicsBeginImageContextWithOptions 对我来说也是一个新的。应该更仔细地查看更新...
    • 这应该是正确的答案。效果很好!需要包含 #import 并将框架添加到项目中。
    【解决方案3】:

    实现将任何 UIView 渲染为图像(也适用于视网膜显示)。

    helper.h 文件:

    @interface UIView (Ext) 
    - (UIImage*) renderToImage;
    @end
    

    helper.m 文件中的归属实现:

    #import <QuartzCore/QuartzCore.h>
    
    @implementation UIView (Ext)
    - (UIImage*) renderToImage
    {
      // IMPORTANT: using weak link on UIKit
      if(UIGraphicsBeginImageContextWithOptions != NULL)
      {
        UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
      } else {
        UIGraphicsBeginImageContext(self.frame.size);
      }
    
      [self.layer renderInContext:UIGraphicsGetCurrentContext()];
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();  
      return image;
    }
    

    0.0 是比例因子。应用于位图的比例因子。如果您指定值 0.0,则比例因子设置为设备主屏幕的比例因子。

    QuartzCore.framework也应该放入项目中,因为我们在图层对象上调用函数。

    要在 UIKit 框架上启用弱链接,请单击左侧导航器中的项目项,单击项目目标 -> 构建阶段 -> 链接二进制并在 UIKit 框架上选择“可选”(弱)类型。

    这里是library,具有 UIColor、UIImage、NSArray、NSDictionary 等类似扩展名...

    【讨论】:

    • 检查是否可以使用UIGraphicsBeginImageContextWithOptions 有什么意义?是为了向后兼容吗?
    • 此解决方案还需要 QuartzCore 框架,用于 renderInContext 方法。
    • @pixelfreak 这是因为 UIGraphicsBeginImageContextWithOptions 仅适用于 iOS 4 +。
    • UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);它有效吗?我认为 0.0 替换为 1.0..
    • 有人知道“常规标签”在哪里吗?我没看到。 UIKit 只有“必需”或“可选”的选项。此外,我不得不为 helper.m 关闭 ARC,但仍然出现“renderInContext”未找到的错误。此外,没有实现/使用,所以这个答案真的可以使用一些编辑。如果可以的话,我很想看看它是如何工作的!
    【解决方案4】:

    关键是UIGraphicsBeginImageContextWithOptions的第三个参数是scale,它决定了图像最终会如何被写出。

    如果你总是想要真实的像素尺寸,使用 [[UIScreen mainScreen] scale] 来获取屏幕的当前比例:

    UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);

    如果您在 iPhone4 上使用 scale=1.0,您将得到一个尺寸以 points 为单位的图像,并且结果是从真实像素数按比例缩小的。如果您手动将图像写入 640x960 尺寸(例如:将像素作为第一个参数传递),它实际上将是按比例放大的缩小图像,看起来和您想象的一样糟糕。

    【讨论】:

    • 根据文档,将 scale 参数设置为 0.0 与将其设置为 [[UIScreen mainScreen] scale] 相同。
    【解决方案5】:

    导入 QuartzCore(点击主项目,构建阶段,导入)并在需要的地方添加:

    #import <QuartzCore/QuartzCore.h>
    

    我的 imageViews 是属性,如果不是,请忽略 .self 并将 imageViews 作为参数传递给函数,然后在新的 UIGraphicsCurrentContext 中对两个图像调用 renderInContext

    - (UIImage *)saveImage
    {
        UIGraphicsBeginImageContextWithOptions(self.mainImage.bounds.size, NO, 0.0);
    
        [self.backgroundImage.layer renderInContext:UIGraphicsGetCurrentContext()];
        [self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()];
    
        UIImage *savedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return savedImage;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 2013-12-20
      • 1970-01-01
      • 2019-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多