为啥这些图像不同 - [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 元素用于标题徽标或背景图像是不是更好,为啥? [复制]
为啥使用 matplotlib 无法正确显示 CIFAR-10 图像?