【问题标题】:Why do these images differ - [img drawInRect:] problem为什么这些图像不同 - [img drawInRect:] 问题
【发布时间】:2021-03-02 15:34:55
【问题描述】:

这几天一直在苦苦挣扎。我从一些数据通过算法创建图像。我还需要拍摄图像并重新创建数据,所以我想实现一个准确的双向操作,数据 -> 图像和图像 -> 数据,比如 d1 -> i1 -> d2。

然后我遇到了一些错误,经过一番挣扎后,我意识到 d1 != d2!

大部分问题出现在图像的右下角,但是,由于创建了下面的测试代码,我注意到问题似乎比这更广泛。

下面的代码说明了这个问题的核心,即[img drawInRect:] 消息。似乎如果您有一些图像并以某个矩形绘制它,那么无论您使用缩放、插入和混合模式等做什么,它都不会准确地返回原始图像。

所以我的问题是:如何使用[img drawInRect:] 准确地渲染img

这里有一些示例代码来说明问题。

#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIImageView * topImage;
@property (weak, nonatomic) IBOutlet UIImageView * botImage;

@end

@implementation ViewController

- (IBAction)drawAction:(id)sender
{
    CGFloat w = self.topImage.bounds.size.width / 20;
    CGFloat h = self.topImage.bounds.size.height / 20;

    // Create random image
    UIGraphicsImageRendererFormat * format = UIGraphicsImageRendererFormat.defaultFormat;

    format.scale = 1;

    UIImage * top = [[[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake ( w, h )
                                format:format]
             imageWithActions: ^ ( UIGraphicsImageRendererContext * ctx )
    {
        for ( CGFloat x = 0; x < w; x ++ )
        {
            for ( CGFloat y = 0; y < w; y ++ )
            {
                if ( arc4random_uniform ( 2 ) )
                {
                    [ctx fillRect:CGRectMake( x, y, 1, 1 )];
                }
            }
        }
    }];

    // Duplicate image
    UIImage * bot = [[[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake ( w, h )
                                format:format]
             imageWithActions: ^ ( UIGraphicsImageRendererContext * ctx )
    {
        [top drawInRect:CGRectMake ( 0, 0, w, h )];
    }];

    // Done
    self.topImage.image = top;
    self.botImage.image = bot;
}

@end

这是一个标准的视图控制器,有两个图像视图和一个按钮,如下所示。

在最初的问题中,我没有像这里那样按比例缩小 20 - 20 只是为了说明,但如果你以 1 的比例工作,这没有什么区别。

注意两个图像之间的区别 - 特别注意右下角!为什么会有差异?

FWIW 绘制图像后,我访问图像数据并从那里构建数据(例如 d2)。有时需要缩放图像,因此我想先使用[img drawInRect:] 来渲染图像,然后再使用图像数据。如果图像已经是正确的尺寸,那么我直接使用图像数据并且回避了这个问题,但是当尺寸不同时我仍然需要使用[img drawInRect:],我希望[img drawInRect:]忠实于原始!

TIA

【问题讨论】:

    标签: ios objective-c


    【解决方案1】:

    几乎可以解决。

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (weak, nonatomic) IBOutlet UIImageView * topImage;
    @property (weak, nonatomic) IBOutlet UIImageView * botImage;
    
    @end
    
    @implementation ViewController
    
    - ( void ) viewDidLoad
    {
        super.viewDidLoad;
    
        self.topImage.layer.magnificationFilter = kCAFilterNearest;
        self.botImage.layer.magnificationFilter = kCAFilterNearest;
    }
    
    - ( IBAction ) drawAction:( id ) sender
    {
        CGFloat wt = self.topImage.bounds.size.width / 20;
        CGFloat ht = self.topImage.bounds.size.height / 20;
    
        // Create random image
        UIGraphicsImageRendererFormat * format = UIGraphicsImageRendererFormat.defaultFormat;
    
        format.scale = 1;
    
        UIImage * top = [[[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake ( wt, ht )
                                    format:format]
                 imageWithActions: ^ ( UIGraphicsImageRendererContext * ctx )
        {
            CGContextSetShouldAntialias ( ctx.CGContext, NO );
            CGContextSetBlendMode ( ctx.CGContext, kCGBlendModeCopy );
    
            for ( CGFloat x = 0; x < wt; x ++ )
            {
                for ( CGFloat y = 0; y < wt; y ++ )
                {
                    if ( arc4random_uniform ( 2 ) )
                    {
                        [ctx fillRect:CGRectMake( x, y, 1, 1 )];
                    }
                }
            }
        }];
    
        // Duplicate image
        CGFloat wb = self.topImage.bounds.size.width / 10;
        CGFloat hb = self.topImage.bounds.size.height / 10;
    
        UIImage * bot = [[[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake ( wb, hb )
                                    format:format]
                 imageWithActions: ^ ( UIGraphicsImageRendererContext * ctx )
        {
            CGContextSetInterpolationQuality ( ctx.CGContext, kCGInterpolationNone );
            CGContextSetShouldAntialias ( ctx.CGContext, NO );
    
            [top drawInRect:CGRectMake ( 0, 0, wb, hb )];
            // Use this if images are the same ...
            // [top drawAsPatternInRect:CGRectMake ( 0, 0, w, h )];
        }];
    
        // Done
        self.topImage.image = top;
        self.botImage.image = bot;
    }
    
    @end
    

    在这个解决方案中,注意两个图像的比例是不同的,只是为了说明。

    [img drawInRect:] 只是不想参加聚会,并且仍然存在这个问题,尤其是在右下角,对于缩放图像,如下例所示。

    似乎缩放搞砸了,所以如果两个图像的尺寸相同,请使用例如[img drawAsPatternInRect:] 在 cmets 中也有说明。否则,当您扩展时,请准备一些损失。此外,如果您将鼻子靠近屏幕并尝试通过它查看,您可能会看到乔布斯的图像。

    【讨论】:

      猜你喜欢
      • 2012-10-26
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2019-11-03
      相关资源
      最近更新 更多