Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 如何从3D转换的UIImageView创建/渲染UIImage?_Iphone_Cocoa Touch_Core Animation - Fatal编程技术网

Iphone 如何从3D转换的UIImageView创建/渲染UIImage?

Iphone 如何从3D转换的UIImageView创建/渲染UIImage?,iphone,cocoa-touch,core-animation,Iphone,Cocoa Touch,Core Animation,将3d变换应用到UIImageView.layer后,我需要将生成的“视图”保存为新的UIImage。。。一开始似乎是一项简单的任务:-)但到目前为止运气不好,搜索也没有发现任何线索:-(所以我希望有人能给我指出正确的方向 有一个非常简单的iPhone项目可用 谢谢 - (void)transformImage { float degrees = 12.0; float zDistance = 250; CATransform3D transform3D = CATran

将3d变换应用到UIImageView.layer后,我需要将生成的“视图”保存为新的UIImage。。。一开始似乎是一项简单的任务:-)但到目前为止运气不好,搜索也没有发现任何线索:-(所以我希望有人能给我指出正确的方向

有一个非常简单的iPhone项目可用

谢谢

- (void)transformImage {
    float degrees = 12.0;
    float zDistance = 250;
    CATransform3D transform3D = CATransform3DIdentity;
    transform3D.m34 = 1.0 / zDistance; // the m34 cell of the matrix controls perspective, and zDistance affects the "sharpness" of the transform
    transform3D = CATransform3DRotate(transform3D, DEGREES_TO_RADIANS(degrees), 1, 0, 0); // perspective transform on y-axis
    imageView.layer.transform = transform3D;
}

/* FAIL : capturing layer contents doesn't get the transformed image -- just the original

CGImageRef newImageRef = (CGImageRef)imageView.layer.contents;

UIImage *image = [UIImage imageWithCGImage:newImageRef];

*/


/* FAIL : docs for renderInContext states that it does not render 3D transforms

UIGraphicsBeginImageContext(imageView.image.size);

[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

*/
//
// header
//
#import <QuartzCore/QuartzCore.h>
#define DEGREES_TO_RADIANS(x) x * M_PI / 180
UIImageView *imageView;
@property (nonatomic, retain) IBOutlet UIImageView *imageView;

//
// code
//
@synthesize imageView;

- (void)transformImage {
    float degrees = 12.0;
    float zDistance = 250;
    CATransform3D transform3D = CATransform3DIdentity;
    transform3D.m34 = 1.0 / zDistance; // the m34 cell of the matrix controls perspective, and zDistance affects the "sharpness" of the transform
    transform3D = CATransform3DRotate(transform3D, DEGREES_TO_RADIANS(degrees), 1, 0, 0); // perspective transform on y-axis
    imageView.layer.transform = transform3D;
}

- (UIImage *)captureView:(UIImageView *)view {
    UIGraphicsBeginImageContext(view.frame.size);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

- (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSString *title = @"Save to Photo Album";
    NSString *message = (error ? [error description] : @"Success!");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

- (IBAction)saveButtonClicked:(id)sender {
    UIImage *newImage = [self captureView:imageView];
    UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), nil);  
}
-(无效)转换图像{
浮动度=12.0;
浮动距离=250;
CATTransferM3D transform3D=CATTransferM3D实体;
transform3D.m34=1.0/zDistance;//矩阵的m34单元格控制透视,zDistance影响变换的“清晰度”
transform3D=CATTransformM3dRotate(transform3D,度到弧度,1,0,0);//y轴上的透视变换
imageView.layer.transform=transform3D;
}
/*失败:捕获层内容不会得到转换后的图像——只是原始图像
CGImageRef newImageRef=(CGImageRef)imageView.layer.contents;
UIImage*image=[UIImage imageWithCGImage:newImageRef];
*/
/*失败:RenderContext文档声明它不渲染3D变换
UIGraphicsBeginImageContext(imageView.image.size);
[imageView.layer RenderContext:UIGraphicsGetCurrentContext()];
UIImage*image=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsSendImageContext();
*/
//
//标题
//
#进口
#定义度到弧度(x)x*M\u PI/180
UIImageView*图像视图;
@属性(非原子,保留)IBUIImageView*imageView;
//
//代码
//
@综合图像视图;
-(无效)转换图像{
浮动度=12.0;
浮动距离=250;
CATTransferM3D transform3D=CATTransferM3D实体;
transform3D.m34=1.0/zDistance;//矩阵的m34单元格控制透视,zDistance影响变换的“清晰度”
transform3D=CATTransformM3dRotate(transform3D,度到弧度,1,0,0);//y轴上的透视变换
imageView.layer.transform=transform3D;
}
-(UIImage*)captureView:(UIImageView*)视图{
UIGraphicsBeginImageContext(view.frame.size);
[view.layer RenderContext:UIGraphicsGetCurrentContext()];
UIImage*newImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsSendImageContext();
返回新图像;
}
-(void)ImageSavedPhotosAlbum:(UIImage*)图像未完成SaveingWitherRor:(NSError*)错误上下文信息:(void*)上下文信息{
NSString*title=@“保存到相册”;
NSString*消息=(错误?[错误描述]:@“成功!”);
UIAlertView*alert=[[UIAlertView alloc]initWithTitle:title消息:消息委托:nil CancelButtontile:@“确定”其他Buttontiles:nil];
[警报显示];
[警报发布];
}
-(iAction)保存按钮单击:(id)发件人{
UIImage*newImage=[self captureView:imageView];
UIImageWriteToSavedPhotosAlbum(新图像,自我,@selector(ImageSavedPhotosAlbum:didFinishSavingWithError:contextInfo:),无);
}

理论上,您可以在黑色背景上快速渲染到屏幕后使用(现在允许的)未记录的调用UIGetScreenImage(),但实际上这会很慢而且很难看,所以不要使用它;p.

您看过这个吗?

captureView:
方法中,尝试替换这一行:

[view.layer renderInContext:UIGraphicsGetCurrentContext()];
为此:

[view.layer.superlayer renderInContext:UIGraphicsGetCurrentContext()];
您可能需要调整用于创建图像上下文的大小

我在API文档中没有看到任何表示renderInContext:忽略3D转换的内容。但是,转换应用于层,而不是其内容,这就是为什么需要渲染superlayer才能看到应用的转换


请注意,在superview上调用
drawRect:
肯定不起作用,因为
drawRect:
不会绘制子视图。

我与您有同样的问题,我找到了解决方案! 我想旋转UIImageView,因为我将拥有动画。 并保存图像,我使用以下方法:

void CGContextConcatCTM(CGContextRef c, CGAffineTransform transform)
transform参数是UIImageView!的转换。因此,您对imageView所做的任何操作都将与对image!所做的操作相同!。 我写了一个UIImage的分类方法

-(UIImage *)imageRotateByTransform:(CGAffineTransform)transform{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
rotatedViewBox.transform = transform;
CGSize rotatedSize = rotatedViewBox.frame.size;
[rotatedViewBox release];

// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();

// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

//Rotate the image context using tranform
CGContextConcatCTM(bitmap, transform);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}


希望这能对您有所帮助。

我发现至少在我的案例中有效的一个解决方案是将
CALayer
子类化。当
RenderContext:
消息发送到一个层时,该层会自动将该消息转发到其所有子层。因此我所要做的就是将
CALayer
子类化并覆盖
RenderContextxt:
方法,并在提供的上下文中呈现需要呈现的内容

例如,在我的代码中,我有一个层,我将其内容设置为箭头图像:

UIImage *image = [UIImage imageNamed:@"arrow.png"];
MYLayer *myLayer = [[CALayer alloc] init];
[myLayer setContents:(__bridge id)[image CGImage]];
[self.mainLayer addSublayer:myLayer];
现在,当我在箭头Y轴上应用3D 180度旋转并尝试执行
[self.mainLayer renderInContext:context]
之后,我仍然得到未旋转的图像

因此,在我的子类
MyLayer
中,我重写了
renderInContext:
,并使用已旋转的图像在提供的上下文中绘制:

- (void)renderInContext:(CGContextRef)ctx
{
    NSLog(@"Rendered in context");
    UIImage *image = [UIImage imageNamed:@"arrow_rotated.png"];
    CGContextDrawImage(ctx, self.bounds, image.CGImage);
}

这在我的案例中起到了作用,但是我可以看到,如果你正在进行大量的3D变换,你可能无法为每个可能的场景准备好图像。在许多其他情况下,虽然在传递的上下文中应该可以使用2D变换渲染3D变换的结果。例如,在我的案例中,而不是使用不同的图像
arrow\u rotated.png
我可以使用
arrow.png
图像,镜像它并在上下文中绘制它。

我最终使用视图变换的倒数在CPU上创建了一种每像素像素的渲染方法

基本上,它将原始UIImageView渲染为UIImage,然后UIImage中的每个像素乘以逆变换矩阵生成变换后的UIImage

RenderUIImageView.h

#import <UIKit/UIKit.h>
#import <QuartzCore/CATransform3D.h>
#import <QuartzCore/CALayer.h>

@interface RenderUIImageView : UIImageView

- (UIImage *)generateImage;

@end
#导入
#进口
#进口
@接口RenderUIImageView:UIImageView
-(UIImage*)生成图像;
@结束
Renderuimag
#import "RenderUIImageView.h"

@interface RenderUIImageView()

@property (assign) CATransform3D transform;
@property (assign) CGRect rect;

@property (assign) float denominatorx;
@property (assign) float denominatory;
@property (assign) float denominatorw;

@property (assign) float factor;

@end

@implementation RenderUIImageView


- (UIImage *)generateImage
{

    _transform = self.layer.transform;

    _denominatorx = _transform.m12 * _transform.m21 - _transform.m11  * _transform.m22 + _transform.m14 * _transform.m22 * _transform.m41 - _transform.m12 * _transform.m24 * _transform.m41 - _transform.m14 * _transform.m21 * _transform.m42 +
    _transform.m11 * _transform.m24 * _transform.m42;

    _denominatory = -_transform.m12 *_transform.m21 + _transform.m11 *_transform.m22 - _transform.m14 *_transform.m22 *_transform.m41 + _transform.m12 *_transform.m24 *_transform.m41 + _transform.m14 *_transform.m21 *_transform.m42 -
    _transform.m11* _transform.m24 *_transform.m42;

    _denominatorw = _transform.m12 *_transform.m21 - _transform.m11 *_transform.m22 + _transform.m14 *_transform.m22 *_transform.m41 - _transform.m12 *_transform.m24 *_transform.m41 - _transform.m14 *_transform.m21 *_transform.m42 +
    _transform.m11 *_transform.m24 *_transform.m42;

    _rect = self.bounds;

    if (UIGraphicsBeginImageContextWithOptions != NULL) {

        UIGraphicsBeginImageContextWithOptions(_rect.size, NO, 0.0);
    } else {
        UIGraphicsBeginImageContext(_rect.size);
    }

    if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
        ([UIScreen mainScreen].scale == 2.0)) {
        _factor = 2.0f;
    } else {
        _factor = 1.0f;
    }


    UIImageView *img = [[UIImageView alloc] initWithFrame:_rect];
    img.image = self.image;

    [img.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *source = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CGContextRef ctx;
    CGImageRef imageRef = [source CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    unsigned char *inputData = malloc(height * width * 4);
    unsigned char *outputData = malloc(height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;

    CGContextRef context = CGBitmapContextCreate(inputData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    context = CGBitmapContextCreate(outputData, width, height,
                                    bitsPerComponent, bytesPerRow, colorSpace,
                                    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);


    for (int ii = 0 ; ii < width * height ; ++ii)
    {
        int x = ii % width;
        int y = ii / width;
        int indexOutput = 4 * x + 4 * width * y;

        CGPoint p = [self modelToScreen:(x*2/_factor - _rect.size.width)/2.0 :(y*2/_factor - _rect.size.height)/2.0];

        p.x *= _factor;
        p.y *= _factor;

        int indexInput = 4*(int)p.x + (4*width*(int)p.y);

        if (p.x >= width || p.x < 0 || p.y >= height || p.y < 0 || indexInput >  width * height *4)
        {
            outputData[indexOutput] = 0.0;
            outputData[indexOutput+1] = 0.0;
            outputData[indexOutput+2] = 0.0;
            outputData[indexOutput+3] = 0.0;

        }
        else
        {
            outputData[indexOutput] = inputData[indexInput];
            outputData[indexOutput+1] = inputData[indexInput + 1];
            outputData[indexOutput+2] = inputData[indexInput + 2];
            outputData[indexOutput+3] = 255.0;
        }
    }

    ctx = CGBitmapContextCreate(outputData,CGImageGetWidth( imageRef ),CGImageGetHeight( imageRef ),8,CGImageGetBytesPerRow( imageRef ),CGImageGetColorSpace( imageRef ), kCGImageAlphaPremultipliedLast );

    imageRef = CGBitmapContextCreateImage (ctx);

    UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
    CGContextRelease(ctx);
    free(inputData);
    free(outputData);
    return rawImage;
}

- (CGPoint) modelToScreen : (float) x: (float) y
{
    float xp = (_transform.m22 *_transform.m41 - _transform.m21 *_transform.m42 - _transform.m22* x + _transform.m24 *_transform.m42 *x + _transform.m21* y - _transform.m24* _transform.m41* y) / _denominatorx;        
    float yp = (-_transform.m11 *_transform.m42 + _transform.m12 * (_transform.m41 - x) + _transform.m14 *_transform.m42 *x + _transform.m11 *y - _transform.m14 *_transform.m41* y) / _denominatory;        
    float wp = (_transform.m12 *_transform.m21 - _transform.m11 *_transform.m22 + _transform.m14*_transform.m22* x - _transform.m12 *_transform.m24* x - _transform.m14 *_transform.m21* y + _transform.m11 *_transform.m24 *y) / _denominatorw;

    CGPoint result = CGPointMake(xp/wp, yp/wp);
    return result;
}

@end
UIGraphicsBeginImageContextWithOptions(viewToRender.bounds.size, YES, 0);
[viewToRender drawViewHierarchyInRect:viewToRender.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageView.layer.transform = someTransform3d
 imageView.transform = CATransform3DGetAffineTransform(someTransform3d)
extension UIView {
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}
let image = imageView.asImage()