我有一个CGImage,显示在由UIScrollView控制的UIView中。图像通常是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)调用drawRect ,0,1680,1050)。
为什么?
答案 0 :(得分:3)
Apple提供的一个有趣的示例代码项目可能会对您有所帮助。它被称为Large Image Downsizing。它做了很多事情,但真正有趣的部分是TiledImageView.m
。其中,视图的图层类设置为CATiledLayer
:
+ (Cl ass)layerClass {
return [CATiledLayer class];
}
使用init
方法设置了tilesLayer属性:
// 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);
}
每个512x512磁贴都会调用 drawRect:
。但是,传入的_rect
并未在方法中使用。它不必,因为当前上下文的剪切路径设置为正确的区域(正如您将通过CGContextGetClipBoundingBox
的输出看到的)。就像Rob说的那样,可以使用CGContextDrawImage
,只会绘制大图像的请求“平铺”,尽管看起来好像整个图像一次又一次地被绘制。如果您不使用CATiledLayer
,则会一次又一次地绘制整个图像,从而减慢所有内容的速度。但是当你使用CATiledLayer
时,只会绘制当前需要的“图块”,这会让它更快。
我希望这会有所帮助。
答案 1 :(得分:1)
谢谢你的回答。
我观察到传递给drawRect的rect参数的内容与我查询CGContextGetClipBoundingBox()时得到的内容相同。
你建议我应该将我的绘图优化到剪切边界 - 但是我在这里没有做任何计算。我只是在调用CGContextDrawImage()。我可以看到其他程序员抱怨CGContextDrawImage性能不佳,而且从iPhone 3到4显然慢得多。我当然希望性能更好但是现在最大的问题是iOS更新整个图像即使只是一小部分无效(使用setNeedsDisplay)。
通过缩小我的意思是我能够看到更多的图像,但图像缩小了。我不是一直在放大和缩小,但是图像的一小部分会定期更新并调用setNeedsDisplay。当我缩放或平移时它非常缓慢且突然,因为整个屏幕由iOS设置以进行更新。
你是对的,CGContextDrawImage优化实际绘制的内容 - 我可以通过测量操作所需的时间来看到它。
正如您所看到的,我使用malloc分配了我的图像位。还有另一种方法可以分配更好地优化图形处理器的图像位吗?
CGImageCreate是否有更优化的ColorRef模式或其他标志?