在 iOS 4 中保存 UIView 内容,并使用内部图像的实际大小(即放大内容进行保存)

发布于 2024-10-03 02:46:41 字数 326 浏览 4 评论 0原文

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

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

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

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

I have an UIView with many UIImageViews as subviews. The app runs on iOS4 and I use images with retina display resolution (i.e. the images load with scale = 2)

I want to save the contents of the UIView ... BUT ... have the real size of the images inside. I.e. the view has size 200x200 and images with scale=2 inside, I'd like to save a resulting image of 400x400 and all the images with their real size.

Now what comes first to mind is to create a new image context and load again all images inside with scale=1 and that should do, but I was wondering if there is any more elegant way to do that? Seems like a waist of memory and processor time to reload everything again since it's already done ...

p.s. if anyone has an answer - including code would be nice

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

多情出卖 2024-10-10 02:46:41

任何 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 框架上选择“可选”(弱)类型。

这是,具有 UIColor、UIImage、NSArray、NSDictionary 等类似扩展。

Implementation for rendering any UIView to image (working also for retina display).

helper.h file:

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

and belonging implementation in helper.m file:

#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 is the scale factor. The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.

QuartzCore.framework also should be put into the project because we are calling function on the layer object.

To enable weak link on UIKit framework, click on the project item in left navigator, click the project target -> build phases -> link binary and choose "optional" (weak) type on UIKit framework.

Here is library with similar extensions for UIColor, UIImage, NSArray, NSDictionary, ...

皓月长歌 2024-10-10 02:46:41

我已经执行了这样的操作,将 MKMapView 中的引脚保存为 PNG 文件(在视网膜显示中): MKPinAnnotationView:是否有超过三种颜色可用?

以下是执行 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]; 返回文档目录; }

I've performed such thing to save the pins from the MKMapView as a PNG file (in retina display): MKPinAnnotationView: Are there more than three colors available?

Here's an extract of the crucial part that performs the saving of a UIView (theView) using its retina definition:


-(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;
}

把梦留给海 2024-10-10 02:46:41

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

如果您始终想要真实的像素尺寸,请使用 [[UIScreen mainScreen] scale] 获取屏幕的当前比例:

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

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

The key is that the third parameter to UIGraphicsBeginImageContextWithOptions is the scale, which determines how the image will ultimately be written out.

If you always want the real pixel dimensions, use [[UIScreen mainScreen] scale] to get the current scale of the screen:

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

If you use scale=1.0 on iPhone4, you will get an image with its dimension in points and the result is scaled down from the true pixel count. If you manually write the image out to a 640x960 dimension (eg: passing pixels as the first parameter), it will actually be the scaled-down image that is scaled back up which looks about as terrible as you imagine it would look.

深海里的那抹蓝 2024-10-10 02:46:41

难道您不能以所需的大小创建一个新的图形上下文,使用 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();

Couldn't you just create a new graphics context at the desired size, use a CGAffineTransform to scale it down, render the root UIView's root layer, restore the context to the original size and render the image? Haven't tried this for retina content, but this seems to work well for large images that have been scaled down in UIImageViews...

something like:

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();
向日葵 2024-10-10 02:46:41

导入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;
}

Import QuartzCore (Click main project, Build Phases, import) and where you need it add:

#import <QuartzCore/QuartzCore.h>

My imageViews are properties, if your are not, ignore the .self and pass the imageViews into the function as parameters, then call renderInContext on the two images in a new UIGraphicsCurrentContext

- (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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文