2010-11-01 25 views
6

iPhone OS 3.1.3'te bir CATiledLayer kullanmak ve bunu -(void)drawLayer:(CALayer *)layer inContext:(CGContext)context numaralı çizimde yalnızca coregraphics ile yapmak zorundayım.CoreGraphics ile CATiledLayer Çizim CGContextDrawImage

Şimdi iPhone'da koordinat sistemi çevirdi ait sorunlarla ve dönüşümleri kullanarak bunu düzeltmek için nasıl bazı öneriler vardır:

Benim sorundur Bunu işe alamıyorum. PhotoScroller örnek kodunu kullanmaya ve çizim yöntemini yalnızca coregraphics çağrılarıyla değiştirmeye başladım. Eğer ben bir Ölçek koordinat sistemi tersine çevirmek için dönüşümü kullanıyorum ve bir çeviri sol alt köşesine kökeni kaydırmaya dönüşümü görebileceğiniz gibi bu

- (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); 

}

benziyor. Görüntüler doğru bir şekilde çizilir, ancak yalnızca ilk sıradaki karolar çizilir. Çeviri işleminde veya karoların koordinatlarının hesaplanma şekliyle ilgili bir sorun olduğunu düşünüyorum. Tüm bu dönüşümler ile biraz karıştı

:

Bu gibi görünüyor nasıl.

Bonus soru: Retina görüntü resimlerinin çekirdek grafiklerde nasıl ele alınır?

DÜZENLEME: o görüntüler sağlamak için sadece örnek kod orijinal yöntemini aldı Retina görüntüsü üzerinde çalışmaya almak için: Ekranın ölçekli Çekirdek beri göz ardı edilir Prensip olarak

- (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; 
} 

Grafikler piksel noktasında değil noktasında çalışıyor, bu nedenle daha fazla piksel çizmek istendiğinde, ekranı doldurmak için daha fazla CATiledLayer (veya alt tabaka) kullanılıyor.

Teşekkür Thomas

cevap

11

Thomas sürü, ben WWDC 2010 scrollview konuşma izleyerek başladı ve iOS 3.x için drawLayer:inContext içinde çalışmaya az veya hiç belge yoktur Demo kodunu drawRect:'dan drawLayer:inContext:'a taşıdığımda yaptığınız gibi aynı sorunları yaşadım.

Bazı soruşturma

drawLayer:inContext: boyut ve CGContextGetClipBoundingBox(context) döndü rect ofset içinde size drawRect: sana tüm sınırları verir yere. Çizmek istiyorum tam olarak ne olduğunu bana gösterdi.

Bunu bildiğinizde, satır ve sütun yinelemenin yanı sıra kenar karoları için CGRect kavşağını kaldırabilir ve içeriği çevirdiğinizde rect'e çizebilirsiniz.rectTranslateCTM ve ScaleCTM sonra yeniden tanımlanır

- (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); 
    } 
} 

Bildirim o: Ben ile sona erdi kadarıyla

burada.

Ve burada referans

benim imageForScale:row:col fonksiyonudur:

- (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; 
} 

Orada iş biraz düzgün yüksek çözünürlüklü grafikleri desteklemek amacıyla bu iki fonksiyonları üzerine hala yapılacak, ama ancak her konuda güzel görünüyor Bir iPhone 4.

+0

Cevabınız için teşekkür ederiz. UIImage yönteminin doğru çözünürlüğü alması gerektiğinden retina ekranı için doğru görüntüyü almak için [[UIImage imageNamed: @ "imageName"] CGImage] yöntemini kullanamazsınız? – GorillaPatch

+0

Gerçekten güzel çalışıyor! Teşekkürler! Ben temelde görüntü karoları sağlamak için örnek koddan alınan yöntemi kullanıyorum, bu yüzden bir retina ekranda sadece görüntüyü çizmek için farklı bir yakınlaştırmada daha fazla fayans görüntüler. Yöntemi asıl soruya ekledim. – GorillaPatch