2008-11-04 14 views
56

Próbuję uzyskać zaokrąglone rogi na UIImage, co czytam do tej pory, najprostszym sposobem jest użycie obrazów maski. W tym celu użyłem kodu z przykładu iPhone'a TheElements i znalezionego kodu zmiany rozmiaru obrazu. Moim problemem jest to, że resizedImage jest zawsze zerowa i nie znajdę błąd ...UIImage zaokrąglone rogi

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize 
{ 
    CGSize imageSize = [self size]; 
    float width = imageSize.width; 
    float height = imageSize.height; 

    // scaleFactor will be the fraction that we'll 
    // use to adjust the size. For example, if we shrink 
    // an image by half, scaleFactor will be 0.5. the 
    // scaledWidth and scaledHeight will be the original, 
    // multiplied by the scaleFactor. 
    // 
    // IMPORTANT: the "targetHeight" is the size of the space 
    // we're drawing into. The "scaledHeight" is the height that 
    // the image actually is drawn at, once we take into 
    // account the ideal of maintaining proportions 

    float scaleFactor = 0.0; 
    float scaledWidth = targetSize.width; 
    float scaledHeight = targetSize.height; 

    CGPoint thumbnailPoint = CGPointMake(0,0); 

    // since not all images are square, we want to scale 
    // proportionately. To do this, we find the longest 
    // edge and use that as a guide. 

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) 
    { 
     // use the longeset edge as a guide. if the 
     // image is wider than tall, we'll figure out 
     // the scale factor by dividing it by the 
     // intended width. Otherwise, we'll use the 
     // height. 

     float widthFactor = targetSize.width/width; 
     float heightFactor = targetSize.height/height; 

     if (widthFactor < heightFactor) 
      scaleFactor = widthFactor; 
     else 
      scaleFactor = heightFactor; 

     // ex: 500 * 0.5 = 250 (newWidth) 

     scaledWidth = width * scaleFactor; 
     scaledHeight = height * scaleFactor; 

     // center the thumbnail in the frame. if 
     // wider than tall, we need to adjust the 
     // vertical drawing point (y axis) 

     if (widthFactor < heightFactor) 
      thumbnailPoint.y = (targetSize.height - scaledHeight) * 0.5; 

     else if (widthFactor > heightFactor) 
      thumbnailPoint.x = (targetSize.width - scaledWidth) * 0.5; 
    } 


    CGContextRef mainViewContentContext; 
    CGColorSpaceRef colorSpace; 

    colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // create a bitmap graphics context the size of the image 
    mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast); 

    // free the rgb colorspace 
    CGColorSpaceRelease(colorSpace);  

    if (mainViewContentContext==NULL) 
     return NULL; 

    //CGContextSetFillColorWithColor(mainViewContentContext, [[UIColor whiteColor] CGColor]); 
    //CGContextFillRect(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height)); 

    CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage); 

    // Create CGImageRef of the main view bitmap content, and then 
    // release that bitmap context 
    CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext); 
    CGContextRelease(mainViewContentContext); 

    CGImageRef maskImage = [[UIImage imageNamed:@"Mask.png"] CGImage]; 

    CGImageRef resizedImage = CGImageCreateWithMask(mainViewContentBitmapContext, maskImage); 
    CGImageRelease(mainViewContentBitmapContext); 

    // convert the finished resized image to a UIImage 
    UIImage *theImage = [UIImage imageWithCGImage:resizedImage]; 

    // image is retained by the property setting above, so we can 
    // release the original 
    CGImageRelease(resizedImage); 

    // return the image 
    return theImage; 
} 

Odpowiedz

14

Problem polegał na użyciu CGImageCreateWithMask, która zwróciła cały czarny obraz. Rozwiązanie znalazłem w użyciu CGContextClipToMask zamiast:

CGContextRef mainViewContentContext; 
CGColorSpaceRef colorSpace; 

colorSpace = CGColorSpaceCreateDeviceRGB(); 

// create a bitmap graphics context the size of the image 
mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast); 

// free the rgb colorspace 
CGColorSpaceRelease(colorSpace);  

if (mainViewContentContext==NULL) 
    return NULL; 

CGImageRef maskImage = [[UIImage imageNamed:@"mask.png"] CGImage]; 
CGContextClipToMask(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height), maskImage); 
CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage); 


// Create CGImageRef of the main view bitmap content, and then 
// release that bitmap context 
CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext); 
CGContextRelease(mainViewContentContext); 

// convert the finished resized image to a UIImage 
UIImage *theImage = [UIImage imageWithCGImage:mainViewContentBitmapContext]; 
// image is retained by the property setting above, so we can 
// release the original 
CGImageRelease(mainViewContentBitmapContext); 

// return the image 
return theImage; 
+0

miło mi działa – Soniya

0

See here... IMO chyba że koniecznie musisz to zrobić w kodzie, po prostu nałożyć obraz na górze.

Coś wzdłuż linii ...

- (void)drawRect:(CGRect)rect 
{ 
    // Drawing code 
    [backgroundImage drawInRect:rect]; 
    [buttonOverlay drawInRect:rect];  
} 
+0

Staram się unikać robi to w kodzie za pomocą CGImageCreateWithMask, ale zawsze zwraca null. – catlan

+0

Mam na myśli dosłownie narysować kolejny UIImage z zasobu nad nim, aby za rogiem. Zobacz edycję ... – Lounges

5

Nie jesteś rzeczywiście robi coś innego niż skalowanie tam. Musisz "zamaskować" rogi obrazu, przycinając je za pomocą CGPath. Na przykład -

- (void)drawRect:(CGRect)rect { 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextBeginTransparencyLayerWithRect(context, self.frame, NULL); 
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); 
    CGFloat roundRadius = (radius) ? radius : 12.0; 
    CGFloat minx = CGRectGetMinX(self.frame), midx = CGRectGetMidX(self.frame), maxx = CGRectGetMaxX(self.frame); 
    CGFloat miny = CGRectGetMinY(self.frame), midy = CGRectGetMidY(self.frame), maxy = CGRectGetMaxY(self.frame); 

    // draw the arcs, handle paths 
    CGContextMoveToPoint(context, minx, midy); 
    CGContextAddArcToPoint(context, minx, miny, midx, miny, roundRadius); 
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, roundRadius); 
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, roundRadius); 
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, roundRadius); 
    CGContextClosePath(context); 
    CGContextDrawPath(context, kCGPathFill); 
    CGContextEndTransparencyLayer(context); 
} 

Proponuję sprawdzić przewodnik programowania Quartz 2D lub kilka innych próbek.

+0

pierwszą częścią mojego kodu jest skalowanie, ale druga część próbuje zamaskować obraz za pomocą CGImageCreateWithMask. Problem polega na tym, że CGImageCreateWithMask zwraca wartość null i nie wiem dlaczego ... – catlan

1

Powodem to działało z przycinania, a nie z maskowania, wydaje się być przestrzeń kolorów.

Dokumentacja Apple znajduje się poniżej.

maska ​​ Maska. Jeśli maska ​​jest obrazem, musi znajdować się w przestrzeni kolorów DeviceGray, nie może zawierać komponentu alfa i może nie być maskowana przez maskę obrazu lub kolor maskowania. Jeśli maska ​​nie ma tego samego rozmiaru, co obraz określony parametrem obrazu, Quartz skaluje maskę, aby dopasować ją do obrazu.

199

Jeśli używasz UIImageView do wyświetlania obrazu można po prostu wykonaj następujące czynności:

imageView.layer.cornerRadius = 5.0; 
imageView.layer.masksToBounds = YES; 

i dodanie obramowania:

imageView.layer.borderColor = [UIColor lightGrayColor].CGColor; 
imageView.layer.borderWidth = 1.0; 

wierzę, że trzeba będzie importować <QuartzCore/QuartzCore.h> i link do niego, aby powyższy kod zadziałał.

+1

Importowanie i łączenie z czym? – PEZ

+3

Niestety #import jessecurry

+0

okazuje się, że był, ale nie wyświetlał się z powodu wartości mniejszej niż/większej niż. – jessecurry

83

jak o tych linii ...

// Get your image somehow 
UIImage *image = [UIImage imageNamed:@"image.jpg"]; 

// Begin a new image that will be the new image with the rounded corners 
// (here with the size of an UIImageView) 
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); 

// Add a clip before drawing anything, in the shape of an rounded rect 
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds 
          cornerRadius:10.0] addClip]; 
// Draw your image 
[image drawInRect:imageView.bounds]; 

// Get the image, here setting the UIImageView image 
imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 

// Lets forget about that we were drawing 
UIGraphicsEndImageContext(); 
+1

Awesome. Dziękuję Ci. –

+3

Oto przydatna kategoria dla Uibutton https://gist.github.com/5804125 – Barry

+1

Zasługujesz na medal, proszę pana. – Sadjad

4
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight) 
{ 
    float fw, fh; 
    if (ovalWidth == 0 || ovalHeight == 0) { 
    CGContextAddRect(context, rect); 
    return; 
    } 
    CGContextSaveGState(context); 
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect)); 
    CGContextScaleCTM (context, ovalWidth, ovalHeight); 
    fw = CGRectGetWidth (rect)/ovalWidth; 
    fh = CGRectGetHeight (rect)/ovalHeight; 
    CGContextMoveToPoint(context, fw, fh/2); 
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); 
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); 
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); 
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); 
    CGContextClosePath(context); 
    CGContextRestoreGState(context); 
} 

+ (UIImage *)imageWithRoundCorner:(UIImage*)img andCornerSize:(CGSize)size 
{ 
    UIImage * newImage = nil; 

    if(nil != img) 
    { 
     @autoreleasepool { 
     int w = img.size.width; 
     int h = img.size.height; 

     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
     CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst); 

     CGContextBeginPath(context); 
     CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height); 
     addRoundedRectToPath(context, rect, size.width, size.height); 
     CGContextClosePath(context); 
     CGContextClip(context); 

     CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage); 

     CGImageRef imageMasked = CGBitmapContextCreateImage(context); 
     CGContextRelease(context); 
     CGColorSpaceRelease(colorSpace); 
     [img release]; 

     newImage = [[UIImage imageWithCGImage:imageMasked] retain]; 
     CGImageRelease(imageMasked); 

     } 
    } 

    return newImage; 
} 
2

Cześć chłopaki spróbuj tego kodu,

+ (UIImage *)roundedRectImageFromImage:(UIImage *)image withRadious:(CGFloat)radious { 

if(radious == 0.0f) 
    return image; 

if(image != nil) { 

    CGFloat imageWidth = image.size.width; 
    CGFloat imageHeight = image.size.height; 

    CGRect rect = CGRectMake(0.0f, 0.0f, imageWidth, imageHeight); 
    UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0]; 
    const CGFloat scale = window.screen.scale; 
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextBeginPath(context); 
    CGContextSaveGState(context); 
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect)); 
    CGContextScaleCTM (context, radious, radious); 

    CGFloat rectWidth = CGRectGetWidth (rect)/radious; 
    CGFloat rectHeight = CGRectGetHeight (rect)/radious; 

    CGContextMoveToPoint(context, rectWidth, rectHeight/2.0f); 
    CGContextAddArcToPoint(context, rectWidth, rectHeight, rectWidth/2.0f, rectHeight, radious); 
    CGContextAddArcToPoint(context, 0.0f, rectHeight, 0.0f, rectHeight/2.0f, radious); 
    CGContextAddArcToPoint(context, 0.0f, 0.0f, rectWidth/2.0f, 0.0f, radious); 
    CGContextAddArcToPoint(context, rectWidth, 0.0f, rectWidth, rectHeight/2.0f, radious); 
    CGContextRestoreGState(context); 
    CGContextClosePath(context); 
    CGContextClip(context); 

    [image drawInRect:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)]; 

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return newImage; 
} 

return nil; 
} 

Cheers !!!

22

I stworzył UIImage -extension w szybki, oparty na wielkim odpowiedź @ epatel za:

extension UIImage{ 
    var roundedImage: UIImage { 
     let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size) 
     UIGraphicsBeginImageContextWithOptions(self.size, false, 1) 
     UIBezierPath(
      roundedRect: rect, 
      cornerRadius: self.size.height 
      ).addClip() 
     self.drawInRect(rect) 
     return UIGraphicsGetImageFromCurrentImageContext() 
    } 
} 

testowane w Storyboard:

storyboard

+0

Świetne .. Chciałbym dokonać niewielkiej zmiany w zakresie skalowania zaokrąglonego obrazu. Jeśli użyjesz kodu w niezmienionej formie, wpłynie to na rozdzielczość obrazu.Tak więc wprowadziłem niewielką zmianę w kodzie, jak podano; let window = UIApplication.sharedApplication(). Windows [0]; UIGraphicsBeginImageContextWithOptions (self.size, false, window.screen.scale) –

+1

Czy "cornerRadius" nie powinien mieć wartości 'self.size.height/2'? –

+0

@IulianOnofrei, który ma dla mnie idealny sens :) – denis631

0

do tworzenia obrazu rogiem możemy użyć kwarccore.

Pierwsze Jak dodać strukturę QuartzCore?

Click project -Targets 
    ->project 
     ->BuildPhase 
      ->Link Binary with Libraries 
      ->Then click + symbol finally select from list and add it 

albo

Click project -Targets 
    ->Targets 
     ->general 
     ->Linked Frameworks and Libraries 
      ->Then click + symbol finally select from list and add the QuartzCore framework 

teraz importować

#import <QuartzCore/QuartzCore.h> 

w ViewController

Następnie w metodzie viewDidLoad

self.yourImageView.layer.cornerRadius = 5.0; 
self.yourImageView.layer.borderWidth = 1.0f; 
self.yourImageView.layer.borderColor = [UIColor blackColor].CGColor; 
self.yourImageView.layer.masksToBounds = YES; 
+0

Edytowałem swoją odpowiedź, sprawdź teraz. Nie głosuj. – user3182143

0

Utworzenie zaokrąglonego obrazu przy użyciu wymiaru obrazu jest bardzo proste.

cell.messageImage.layer.cornerRadius = image.size.width/2 
cell.messageImage.layer.masksToBounds = true 
+0

Powinien być wielkością ramki – Idan

1

okazało się najlepszym i prosty sposób robić to w sposób następujący (brak odpowiedzi to zrobił):

UIImageView *imageView; 

imageView.layer.cornerRadius = imageView.frame.size.width/2.0f; 
imageView.layer.masksToBounds = TRUE; 

Całkiem proste i odbywa się to prawo.

0

Chciałem okrążyć rogi pudełka UIImage w moim scenorysie. Miałem IBOutlet dla mojej nazwy UII o nazwie image. Po przeczytaniu kilku postów po prostu dodałem 3 wiersze i to działało idealnie.

import UIKit 

Następnie w viewDidLoad:

image.layer.cornerRadius = 20.0 

image.layer.masksToBounds = true 

To dla iOS 11,1 w Xcode 9.

Powiązane problemy