为啥这些图像不同 - [img drawInRect:] 问题

Posted

技术标签:

【中文标题】为啥这些图像不同 - [img drawInRect:] 问题【英文标题】: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

【问题讨论】:

【参考方案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 中也有说明。否则,当您扩展时,请准备一些损失。此外,如果您将鼻子靠近屏幕并尝试通过它查看,您可能会看到乔布斯的图像。

【讨论】:

以上是关于为啥这些图像不同 - [img drawInRect:] 问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UMN-Mapserver 将 ERDAS 图像文件 (.img) 显示为白色形状?

将 IMG 元素用于标题徽标或背景图像是不是更好,为啥? [复制]

CSS 背景图像的缩放比例与 <img> 不同? [复制]

为啥使用 matplotlib 无法正确显示 CIFAR-10 图像?

在将图像分配给 img 标签之前使用 javascript 调整图像大小

MATLAB矩阵保存为图像问题,为啥保存图像为空白? RGB值为255。