使用CoreGraphics CGContextDrawImage在CATiledLayer中绘图 [英] Drawing in CATiledLayer with CoreGraphics CGContextDrawImage

查看:153
本文介绍了使用CoreGraphics CGContextDrawImage在CATiledLayer中绘图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在iPhone OS 3.1.3中使用CATiledLayer并且这样做所有绘制 - (void)drawLayer:(CALayer *)图层inContext:(CGContext)context 只能用coregraphics完成。

I would like to use a CATiledLayer in iPhone OS 3.1.3 and to do so all drawing in -(void)drawLayer:(CALayer *)layer inContext:(CGContext)context has to be done with coregraphics only.

现在我遇到iPhone上翻转坐标系的问题,并且有一些建议如何使用它来修复它转换:

Now I run into the problems of the flipped coordinate system on the iPhone and there are some suggestions how to fix it using transforms:

  • Image is drawn upside down
  • CATiledLayer or CALayer not working

我的问题是我不能让它工作。我开始使用PhotoScroller示例代码并仅使用coregraphics调用替换绘图方法。看起来像这样

My problem is that I cannot get it to work. I started using the PhotoScroller sample code and replacing the drawing method with coregraphics calls only. It looks like this

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context {
CGContextSaveGState(context);
CGRect rect = CGContextGetClipBoundingBox(context);
CGFloat scale = CGContextGetCTM(context).a;
CGContextConcatCTM(context, CGAffineTransformMakeTranslation(0.f, rect.size.height));
CGContextConcatCTM(context, CGAffineTransformMakeScale(1.f, -1.f));

CATiledLayer *tiledLayer = (CATiledLayer *)layer;
CGSize tileSize = tiledLayer.tileSize;


tileSize.width /= scale;
tileSize.height /= scale;
// calculate the rows and columns of tiles that intersect the rect we have been asked to draw
int firstCol = floorf(CGRectGetMinX(rect) / tileSize.width);
int lastCol = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
int firstRow = floorf(CGRectGetMinY(rect) / tileSize.height);
int lastRow = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);
for (int row = firstRow; row <= lastRow; row++) {
    for (int col = firstCol; col <= lastCol; col++) {
     //   if (row == 0 ) continue;
        UIImage *tile = [self tileForScale:scale row:row col:col];
        CGImageRef tileRef = [tile CGImage];
        CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row,
                                     tileSize.width, tileSize.height);
        // if the tile would stick outside of our bounds, we need to truncate it so as to avoid
        // stretching out the partial tiles at the right and bottom edges
        tileRect = CGRectIntersection(self.bounds, tileRect);
        NSLog(@"row:%d, col:%d, x:%.0f y:%.0f, height:%.0f, width:%.0f", row, col,tileRect.origin.x, tileRect.origin.y, tileRect.size.height, tileRect.size.width);

        //[tile drawInRect:tileRect];
        CGContextDrawImage(context, tileRect, tileRef);
// just to draw the row and column index in the tile and mark the origin of the tile with a red line        
        if (self.annotates) {
            CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor]CGColor]);
            CGContextSetLineWidth(context, 6.0 / scale);
            CGContextStrokeRect(context, tileRect);
            CGContextSetStrokeColorWithColor(context, [[UIColor redColor]CGColor]);
            CGContextMoveToPoint(context, tileRect.origin.x, tileRect.origin.y);
            CGContextAddLineToPoint(context, tileRect.origin.x+100.f, tileRect.origin.y+100.f);
            CGContextStrokePath(context);
            CGContextSetStrokeColorWithColor(context, [[UIColor redColor]CGColor]);
            CGContextSetFillColorWithColor(context, [[UIColor whiteColor]CGColor]);
            CGContextSelectFont(context, "Courier", 128, kCGEncodingMacRoman);
            CGContextSetTextDrawingMode(context, kCGTextFill);
            CGContextSetShouldAntialias(context, true);
            char text[30]; 
            int length = sprintf(text,"row:%d col:%d",row,col);
            CGContextSaveGState(context);
            CGContextShowTextAtPoint(context, tileRect.origin.x+110.f,tileRect.origin.y+100.f, text, length);
            CGContextRestoreGState(context);
        }
    }
}

CGContextRestoreGState(context);

}

正如你所看到的我我使用Scale变换来反转坐标系,使用平移变换将原点移动到左下角。图像绘制正确但只绘制了第一行图块。我认为翻译操作或计算拼贴坐标的方式存在问题。

As you can see I am using a Scale transform to invert the coordinate system and a translation transform to shift the origin to the lower left corner. The images draw correctly but only the first row of tiles is being drawn. I think there is a problem with the translation operation or the way the coordinates of the tiles are computed.

这就是它的样子:

我有点困惑所有这些转换。

I am a bit confused with all this transformations.

奖金问题:
如何处理核心图形中的视网膜显示图片?

Bonus question: How would one handle the retina display pictures in core graphics?

编辑:
为了让它在视网膜显示器上工作,我只是从示例代码中提取原始方法来提供图像:

To get it working on the retina display I just took the original method from the sample code to provide the images:

- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col
{
// we use "imageWithContentsOfFile:" instead of "imageNamed:" here because we don't want UIImage to cache our tiles
NSString *tileName = [NSString stringWithFormat:@"%@_%d_%d_%d", imageName, (int)(scale * 1000), col, row];
NSString *path = [[NSBundle mainBundle] pathForResource:tileName ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
return image;
}

原则上,由于Core Graphics正在使用像素不是点因此当被要求绘制更多像素时,会使用更多CATiledLayers(或子图层)来填充屏幕。

In principle the scale of the display is ignored since Core Graphics is working in pixels not points so when asked to draw more pixels, more CATiledLayers (or sublayers) are used to fill the screen.

非常感谢
Thomas

Thanks alot Thomas

推荐答案

Thomas,我开始关注WWDC 2010 ScrollView讲座,很少或根本没有关于<$对于iOS 3.x,c $ c> drawLayer:inContext 。当我将演示代码从 drawRect:移到 drawLayer:inContext:时,我遇到了同样的问题。

Thomas, I started by following the WWDC 2010 ScrollView talk and there is little or no documentation on working within drawLayer:inContext for iOS 3.x. I had the same issues as you do when I moved the demo code from drawRect: across to drawLayer:inContext:.

一些调查显示我在 drawLayer:inContext: rect的大小和偏移量从返回的 CGContextGetClipBoundingBox(上下文)正是您要绘制的内容。其中 drawRect:给你整个界限。

Some investigation showed me that within drawLayer:inContext: the size and offset of rect returned from CGContextGetClipBoundingBox(context) is exactly what you want to draw in. Where drawRect: gives you the whole bounds.

知道这一点你可以删除行和列迭代,以及边缘图块的CGRect交集,只需绘制到一次矩形你翻译了上下文。

Knowing this you can remove the row and column iteration, as well as the CGRect intersection for the edge tiles and just draw to the rect once you've translated the context.

以下是我最终的结果:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
  CGRect rect = CGContextGetClipBoundingBox(ctx);
  CGFloat scale = CGContextGetCTM(ctx).a;

  CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
  CGSize tileSize = tiledLayer.tileSize;
  tileSize.width /= scale;
  tileSize.height /= scale;

  int col = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
  int row = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);

  CGImageRef image = [self imageForScale:scale row:row col:col];

  if(NULL != image) {
    CGContextTranslateCTM(ctx, 0.0, rect.size.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);
    rect = CGContextGetClipBoundingBox(ctx);

    CGContextDrawImage(ctx, rect, image);
    CGImageRelease(image);
  }
}

请注意 rect TranslateCTM ScaleCTM 之后重新定义。

Notice that rect is redefined after the TranslateCTM and ScaleCTM.

这里的参考是我的 imageForScale:row:col 功能:

And for reference here is my imageForScale:row:col function:

- (CGImageRef) imageForScale:(CGFloat)scale row:(int)row col:(int)col {
  CGImageRef image = NULL;
  CGDataProviderRef provider = NULL;
  NSString *filename = [NSString stringWithFormat:@"img_name_here%0.0f_%d_%d",ceilf(scale * 100),col,row];
  NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"png"];

  if(path != nil) {
    NSURL *imageURL = [NSURL fileURLWithPath:path];

    provider = CGDataProviderCreateWithURL((CFURLRef)imageURL);

    image = CGImageCreateWithPNGDataProvider(provider,NULL,FALSE,kCGRenderingIntentDefault); 
    CFRelease(provider);
  }
  return image;
}

为了使这两个功能还有一些工作要做正确支持高分辨率图形,但除了iPhone 4之外,它确实看起来不错。

There's still a bit of work to be done on these two functions in order to support high resolution graphics properly, but it does look nice on everything but an iPhone 4.

这篇关于使用CoreGraphics CGContextDrawImage在CATiledLayer中绘图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆