2008-10-15 16 views
57

मैं गोलाकार कोनों के साथ आईफोन पर छवियों को आकर्षित करने की कोशिश कर रहा हूं, संपर्क ऐप में एक ला संपर्क छवियां। मेरे पास आम तौर पर काम करने वाला कोड है, लेकिन यह कभी-कभी EXEC_BAD_ACCESS - KERN_INVALID_ADDRESS के साथ UIImage ड्राइंग रूटीन के अंदर दुर्घटनाग्रस्त हो जाता है। मैंने सोचा कि यह cropping question से संबंधित हो सकता है, मैंने कुछ हफ्ते पहले पूछा था, लेकिन मेरा मानना ​​है कि मैं क्लिपिंग पथ को सही तरीके से स्थापित कर रहा हूं।UIImage पर गोलाकार कॉर्नर

यहां कोड है जिसका उपयोग मैं कर रहा हूं - जब यह क्रैश नहीं होता है, तो परिणाम ठीक दिखता है और कोई भी समान दिखने वाला दिखता है, वह कोड उधार लेने के लिए स्वतंत्र होता है।

- (UIImage *)borderedImageWithRect: (CGRect)dstRect radius:(CGFloat)radius { 
    UIImage *maskedImage = nil; 

    radius = MIN(radius, .5 * MIN(CGRectGetWidth(dstRect), CGRectGetHeight(dstRect))); 
    CGRect interiorRect = CGRectInset(dstRect, radius, radius); 

    UIGraphicsBeginImageContext(dstRect.size); 
    CGContextRef maskedContextRef = UIGraphicsGetCurrentContext(); 
    CGContextSaveGState(maskedContextRef); 

    CGMutablePathRef borderPath = CGPathCreateMutable(); 
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(180), PNDegreeToRadian(270), NO); 
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(270.0), PNDegreeToRadian(360.0), NO); 
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(0.0), PNDegreeToRadian(90.0), NO); 
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(90.0), PNDegreeToRadian(180.0), NO); 

    CGContextBeginPath(maskedContextRef); 
    CGContextAddPath(maskedContextRef, borderPath); 
    CGContextClosePath(maskedContextRef); 
    CGContextClip(maskedContextRef); 

    [self drawInRect: dstRect]; 

    maskedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    CGContextRestoreGState(maskedContextRef); 
    UIGraphicsEndImageContext(); 

    return maskedImage; 
} 

और यहां क्रैश लॉग है। यह वही दिखता है जब भी मैं इन दुर्घटनाओं

 
Exception Type: EXC_BAD_ACCESS (SIGSEGV) 
Exception Codes: KERN_INVALID_ADDRESS at 0x6e2e6181 
Crashed Thread: 0 

Thread 0 Crashed: 
0 com.apple.CoreGraphics   0x30fe56d8 CGGStateGetRenderingIntent + 4 
1 libRIP.A.dylib     0x33c4a7d8 ripc_RenderImage + 104 
2 libRIP.A.dylib     0x33c51868 ripc_DrawImage + 3860 
3 com.apple.CoreGraphics   0x30fecad4 CGContextDelegateDrawImage + 80 
4 com.apple.CoreGraphics   0x30feca40 CGContextDrawImage + 368 
5 UIKit       0x30a6a708 -[UIImage drawInRect:blendMode:alpha:] + 1460 
6 UIKit       0x30a66904 -[UIImage drawInRect:] + 72 
7 MyApp       0x0003f8a8 -[UIImage(PNAdditions) borderedImageWithRect:radius:] (UIImage+PNAdditions.m:187) 
+0

आप क्यों करते हैं CGContextSaveGState() और CGContextRestoreGState()? प्रलेखन पढ़ना, मुझे लगता है कि राज्य संदर्भ के लिए आंतरिक है, और पूरे संदर्भ को किसी भी तरह से फेंक दिया जाता है। –

+0

क्या आप CGContextBeginPath() और CGContextClosePath() को कॉल करना आवश्यक है? मैंने पाया है कि मैं सिर्फ एक रास्ता बना सकता हूं और CGContextAddPath() को कॉल कर सकता हूं और चीजें ठीक काम करती हैं। साथ ही, CGContextClosePath() के लिए दस्तावेज़ कहते हैं कि "जब आप खुले पथ को भरते या क्लिप करते हैं, तो क्वार्ट्ज आपके लिए सबपैथ को बंद कर देता है", यह सुझाव देते हुए कि इसे स्वयं बंद करने की आवश्यकता नहीं है। – camdez

उत्तर

163

यहाँ एक और भी आसान विधि कि iPhone 3.0 और ऊपर में उपलब्ध है। प्रत्येक व्यू-आधारित ऑब्जेक्ट में एक संबद्ध परत होती है। प्रत्येक परत एक कोने त्रिज्या सेट हो सकता है, यह आप दे देंगे तुम सिर्फ क्या चाहते हैं:

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]]; 
// Get the Layer of any view 
CALayer * l = [roundedView layer]; 
[l setMasksToBounds:YES]; 
[l setCornerRadius:10.0]; 

// You can even add a border 
[l setBorderWidth:4.0]; 
[l setBorderColor:[[UIColor blueColor] CGColor]]; 
+0

शानदार, इसके लिए धन्यवाद! –

+0

जाहिर है, जब मैंने प्रश्न पूछा (2 के तहत।0), लेकिन यह वर्तमान विश्व व्यवस्था (यानी, 3.x) के तहत एक अच्छा जवाब प्रतीत होता है। इसे किसी भी UIView के साथ काम करने का अतिरिक्त लाभ मिला है, जो मुझे यहां वापस लाया। – Jablair

+19

जैसा कि नीचे बताया गया है, #import

4

मैं नहीं कर सकते अपने दुर्घटना में किसी भी अंतर्दृष्टि प्रदान करते हैं में से एक मिलता है, लेकिन मैंने सोचा कि मैं कोनों गोलाई के लिए एक और विकल्प की पेशकश करेगा। मुझे एक ऐसे ऐप्लिकेशन में भी ऐसी ही समस्या आई थी जिस पर मैं काम कर रहा था। किसी भी कोड को लिखने के बजाय मैं एक और छवि को ओवरले कर रहा हूं जो कोनों से बाहर निकलता है।

+0

मैंने एक छवि के साथ मास्किंग करने की कोशिश की और इसे कभी भी विश्वसनीय रूप से काम करने में सक्षम नहीं था। क्या आपके पास कोई संकेत है कि आप इसे कैसे काम करते हैं? यह थोड़ी देर पहले था, इसलिए मुझे बिल्कुल याद नहीं आया कि मैंने क्या कोशिश की, लेकिन मुझे लगता है कि मैं CGImageCreateWithMask, CGImageMaskCreate, और CGContextClipToMask के माध्यम से चला गया। – Jablair

+0

मैं कोड में मास्किंग नहीं कर रहा हूं। मैं बस उस छवि के शीर्ष पर एक और UIImage खींच रहा हूं जिसे मैं मास्क करना चाहता हूं। UIImage में मध्य और काले (मेरे पृष्ठभूमि रंग) किनारों में एक पारदर्शी खंड है जिसे मैं "मुखौटा बंद करना" चाहता हूं। – Lounges

1

यदि यह केवल कुछ समय दुर्घटनाग्रस्त हो जाता है, तो पता लगाएं कि दुर्घटना के मामलों में क्या समान है। क्या हर बार dstRect समान है? क्या छवियां कभी अलग आकार हैं?

इसके अलावा, आपको CGPathRelease(borderPath) की आवश्यकता है, हालांकि मुझे संदेह है कि रिसाव आपकी समस्या का कारण बन रहा है।

+0

रिलीज अनुस्मारक के लिए धन्यवाद। मैंने गलती से टिप्पणी की थी कि कुछ अन्य डिबगिंग कोड के साथ, जिसे मैंने पोस्ट करने से पहले छंटनी की थी। dstRect समान है, लेकिन छवियां अलग-अलग हो सकती हैं क्योंकि वे वेब से डाउनलोड की जाती हैं। मैं इन्हें एक परीक्षक से प्राप्त कर रहा हूं - मैंने इसे खुद को दोबारा नहीं बदला है। – Jablair

3

सबसे आसान तरीका है अपने दृश्य में अक्षम [!] राउंड-रेक्ट [कस्टम नहीं!] बटन एम्बेड करना (इंटरफ़ेस बिल्डर में भी यह सब कर सकता है) और अपनी छवि को इसके साथ जोड़ना है। छवि-सेटिंग संदेश UIButton (UIImageView की तुलना में) के लिए अलग है, लेकिन समग्र क्लज एक आकर्षण की तरह काम करता है। SetImage का उपयोग करें: forState: यदि आप एक केंद्रित आइकन चाहते हैं या सेटबैकग्राउंड छवि: forState: यदि आप पूरी छवि कोनों के साथ कट (जैसे संपर्क) चाहते हैं। बेशक यदि आप अपने ड्रॉरेक्ट में इन छवियों में से कई को प्रदर्शित करना चाहते हैं तो यह सही दृष्टिकोण नहीं है, लेकिन अधिक संभावना है कि एक एम्बेडेड व्यू बिल्कुल वही है जो आपको वैसे भी चाहिए ...

4

यदि आप अपनी विधि (borderedImageWithRect) को कॉल कर रहे हैं पृष्ठभूमि धागे में, क्रैश हो सकता है क्योंकि UIGraphics-functions थ्रेड-सुरक्षित नहीं हैं। ऐसे मामले में, आपको CGBitmapContextCreate() का उपयोग करके एक संदर्भ बनाना होगा - एसडीके से "प्रतिबिंब" नमूना कोड देखें।

+0

fjoachim, क्या आपने वास्तव में यह किया है? मुझे पृष्ठभूमि थ्रेड पर बिटमैप संदर्भ में ड्राइंग करने में समस्या आ रही है। Http://stackoverflow.com/questions/702914/using-core-graphics-cocoa-can-you-draw-to-a-bitmap-context-from-a-background-th – philsquared

2

मैं fjoachim's answer दोहरा दूंगा: अलग थ्रेड पर चलते समय आकर्षित करने का प्रयास करते समय सतर्क रहें, या आपको EXC_BAD_ACCESS त्रुटियां मिल सकती हैं।

मेरे वैकल्पिक हल कुछ इस तरह चला गया: (। मेरे मामले में मैं आकार बदलने था/UIImages स्केलिंग)

UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES]; 

2

मैं वास्तव में iPhone पर एप्पल से किसी के साथ इस बारे में बात करने का मौका मिला न्यूयॉर्क में टेक टॉक। जब हमने इसके बारे में बात की, तो उसे पूरा यकीन था कि यह जारी थ्रेडिंग नहीं था। इसके बजाए, उन्होंने सोचा कि मुझे UIGraphicsBeginImageContext पर कॉल करते समय जेनरेट किए गए ग्राफिक्स संदर्भ को बनाए रखने की आवश्यकता है। ऐसा लगता है कि बनाए रखने के नियमों और नामकरण योजनाओं से निपटने वाले सामान्य नियमों का उल्लंघन करना प्रतीत होता है, लेकिन इस साथी को यकीन था कि वह पहले इस मुद्दे को देखेगा।

यदि स्मृति किसी अन्य धागे से लिखी जा रही थी, तो निश्चित रूप से यह समझाएगा कि मैं कभी-कभी इस मुद्दे को क्यों देख रहा था।

मेरे पास कोड पर फिर से विचार करने और फिक्स का परीक्षण करने का समय नहीं है, लेकिन पीसीहेज़ की टिप्पणी ने मुझे एहसास दिलाया कि मैंने यहां जानकारी पोस्ट नहीं की है।

... जब तक मैं गलत नीचे कि लिखा था और UIGraphicsBeginImageContextCGBitmapContextCreate किया गया है चाहिए ...

21

तो appIconImage, एक UIImageView है तो:

appIconImage.image = [UIImage imageWithContentsOfFile:@"image.png"]; 
appIconImage.layer.masksToBounds = YES; 
appIconImage.layer.cornerRadius = 10.0; 
appIconImage.layer.borderWidth = 1.0; 
appIconImage.layer.borderColor = [[UIColor grayColor] CGColor]; 

और यह भी याद रखें:

#import <QuartzCore/QuartzCore.h> 
24

मैं यहां आगे बढ़ने वाला हूं और वास्तव में शीर्षक में प्रश्न का उत्तर देता हूं।

इस श्रेणी को आज़माएं।

UIImage + additions.h

#import <UIKit/UIKit.h> 

@interface UIImage (additions) 
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS; 
@end 

UIImage + additions.m

#import "UIImage+additions.h" 

@implementation UIImage (additions) 
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS { 
    UIImage *image = self; 

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

    const CGRect RECT = CGRectMake(0, 0, image.size.width, image.size.height); 
    // Add a clip before drawing anything, in the shape of an rounded rect 
    [[UIBezierPath bezierPathWithRoundedRect:RECT cornerRadius:RADIUS] addClip]; 
    // Draw your image 
    [image drawInRect:RECT]; 

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

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

    return imageNew; 
} 
@end 
+0

यह मुझे परेशान करता है कि इस सवाल को इस दिन इतनी सारी हिट मिलती है। यह मुझे यह सोचने के लिए भी परेशान करता है कि जब मैंने प्रश्न पूछा (आईओएस 2.0) तो हमारे पास UIBezierPath जैसी चीजें नहीं थीं। मैन, हम एक लंबा सफर तय कर चुके हैं। – Jablair

+0

@Jablair - ठीक है, एप्पल निर्णय लेने वाली छवियों के रूप में आईओएस 7 में एक परिपत्र विचारों में होना आवश्यक है, अब हमें बहुत सारे परिपत्र UIImages की आवश्यकता है। – ArtOfWarfare

+0

इसे सही उत्तर के रूप में फ़्लैग किया जाना चाहिए, अन्य सभी उत्तरों गलत हैं यदि UIImageView UIViewContentModeScaleToFill सामग्री मोड का उपयोग नहीं करता है। यह किसी भी सामग्री मोड के साथ सही ढंग से काम करता है। – SPQR3

-1

xib या स्टोरीबोर्ड (छवि चौड़ाई और ऊंचाई 41x41) में छवि सेट करें।

FirstViewController.h

@interface.... 

IBOutlet UIImageView *testImg; 

@end 

FirstViewController.m

-(void)viewDidLoad{ 
     testImg.layer.backgroundColor=[[UIColor clearColor] CGColor]; 
     testImg.layer.cornerRadius=20; 
     testImg.layer.masksToBounds = YES; 
    } 
0
UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES]; 
संबंधित मुद्दे