3

我有一个显示在由 UIScrollView 控制的 UIView 中的 CGImage。图像通常是 1680*1050 的 24 位颜色,没有 Alpha 通道。

图像是这样创建的:

CGImageRef bitmapClass::CreateBitmap(int width, int height, int imageSize, int colorDepth, int bytesPerRow)
{
   unsigned char* m_pvBits = malloc(imageSize);

   // Initializt bitmap buffer to black (red, green, blue)
   memset(m_pvBits, 0, imageSize);

   m_DataProviderRef = 
      CGDataProviderCreateWithData(NULL, m_pvBits, imageSize, NULL); 

   m_ColorSpaceRef = 
      CGColorSpaceCreateDeviceRGB();   

   return
      CGImageCreate(width, height, 
                    8, //kBitsPerComponent 
                    colorDepth, 
                    bytesPerRow, 
                    m_ColorSpaceRef, 
                    kCGBitmapByteOrderDefault | kCGImageAlphaNone, 
                    m_DataProviderRef, 
                    NULL, false, kCGRenderingIntentDefault);
}

图像内容通过更改 m_pvBits 中的像素在后台定期更新,并使用以下方法在 UIView 中更新:

[myView setNeedsDisplayInRect:rect];

这会调用 drawRect 来显示图像,如下所示:

- (void)drawRect:(CGRect)rect
{
   CGRect imageRect;
   imageRect.origin = CGPointMake(0.0, 0.0);
   imageRect.size = CGSizeMake(self.imageWidth, self.imageHeight);

   CGContextRef context = UIGraphicsGetCurrentContext();

   CGContextSetInterpolationQuality(context, kCGInterpolationNone);

   // Drawing code
   CGContextDrawImage(context, imageRect, (CGImageRef)pWindow->GetImageRef());
}

只要视图没有缩小(缩小),这种方法就可以很好地工作。我知道'rect'实际上并没有直接在drawRect中使用,但'context'似乎知道CGContextDrawImage应该更新屏幕的哪个部分。

我的问题是,即使我只使用 setNeedsDisplayInRect 使屏幕的一小部分区域无效,但当视图缩小时,整个屏幕都会调用 drawRect。因此,如果我的图像是 1680*1050 并且我使一个小矩形 (x,y,w,h)=(512, 640, 32, 32) 无效,则使用 (x,y,w,h)=(0 , 0, 1680, 1050)。

为什么?

4

2 回答 2

3

Apple 提供了一个有趣的示例代码项目,可能会对您有所帮助。它被称为大图像缩小。它做了很多事情,但真正有趣的部分是TiledImageView.m. 在其中,视图的图层类设置为CATiledLayer

+ (Cl ass)layerClass {
    return [CATiledLayer class];
}

tiledLayer 属性正在init方法中设置:

// Create a new TiledImageView with the desired frame and scale.
-(id)initWithFrame:(CGRect)_frame image:(UIImage*)_image scale:(CGFloat)_scale {
    if ((self = [super initWithFrame:_frame])) {
        self.image = _image;
        imageRect = CGRectMake(0.0f, 0.0f, CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
        imageScale = _scale;
        CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
        // levelsOfDetail and levelsOfDetailBias determine how
        // the layer is rendered at different zoom levels.  This
        // only matters while the view is zooming, since once the 
        // the view is done zooming a new TiledImageView is created
        // at the correct size and scale.
        tiledLayer.levelsOfDetail = 4;
        tiledLayer.levelsOfDetailBias = 4;
        tiledLayer.tileSize = CGSizeMake(512.0, 512.0); 
    }
    return self;
}

最后,这是真正有趣的部分,这是drawRect:实现(NSLog 来自我):

-(void)drawRect:(CGRect)_rect {
    CGContextRef context = UIGraphicsGetCurrentContext();    
    CGContextSaveGState(context);
    // Scale the context so that the image is rendered 
    // at the correct size for the zoom level.
    CGContextScaleCTM(context, imageScale,imageScale);  
    NSLog(@"rect: %@, imageScale: %.4f, clip: %@", NSStringFromCGRect(_rect), imageScale, NSStringFromCGRect(CGContextGetClipBoundingBox(context)));
    CGContextDrawImage(context, imageRect, image.CGImage);
    CGContextRestoreGState(context);    
}

drawRect:为每个 512x512 瓦片调用。_rect但是,在方法内部根本不使用传入的值。不必这样做,因为当前上下文的剪切路径设置为正确的区域(正如您将在 的输出中看到的那样CGContextGetClipBoundingBox)。所以就像 Rob 说的,CGContextDrawImage可以使用并且只绘制大图像的请求“平铺”,尽管看起来好像整个图像一次又一次地绘制。如果您不使用CATiledLayer,则确实会一次又一次地绘制整个图像,这会减慢一切。但是当您使用 时CATiledLayer,只会绘制当前需要的“图块”,这会使其速度更快。

我希望这有帮助。

于 2012-06-26T07:33:14.673 回答
1

谢谢你的回答。

据我观察,传递给 drawRect 的 rect 参数的内容与我查询 CGContextGetClipBoundingBox() 时得到的内容相同。

你建议我应该将我的绘图优化到剪裁范围 - 但我在这里没有做任何计算。我只是在调用 CGContextDrawImage()。我可以看到其他程序员抱怨 CGContextDrawImage 的性能不佳,而且它显然从 iPhone 3 到 iPhone 4 变慢了。我当然希望性能更好,但现在最大的问题是 iOS 更新整个图像,即使只有一小部分无效(使用 setNeedsDisplay)。

缩小是指我可以看到更多图像,但图像缩小了。我不会经常放大和缩小,但图像的一小部分会定期更新并调用 setNeedsDisplay。当我缩放或平移时,它非常缓慢且突然,因为整个屏幕由 iOS 设置为更新。

没错,CGContextDrawImage 优化了实际绘制的内容 - 我可以通过测量操作所花费的时间来看到这一点。

如您所见,我使用 malloc 分配图像位。是否有另一种方法可以分配更适合图形处理器的图像位?

CGImageCreate 是否有更优化的 ColorRef 模式或其他标志?

于 2012-06-24T21:52:14.593 回答