2012-10-02 20 views
8

स्केल नहीं करता है मैं एक त्वरित ऐप विकसित कर रहा हूं जिसमें मेरे पास एक विधि है जिसे नियमित रूप से @ 2x छवि को पुन: सहेजना चाहिए। समस्या यह है कि यहएनएसआईमेज

क्यों? :(नहीं करता है

-(BOOL)createNormalImage:(NSString*)inputRetinaImagePath { 

    NSImage *inputRetinaImage = [[NSImage alloc] initWithContentsOfFile:inputRetinaImagePath]; 



    NSSize size = NSZeroSize; 
    size.width = inputRetinaImage.size.width*0.5; 
    size.height = inputRetinaImage.size.height*0.5; 

    [inputRetinaImage setSize:size]; 


    NSLog(@"%f",inputRetinaImage.size.height); 


    NSBitmapImageRep *imgRep = [[inputRetinaImage representations] objectAtIndex: 0]; 

    NSData *data = [imgRep representationUsingType: NSPNGFileType properties: nil]; 

    NSString *outputFilePath = [[inputRetinaImagePath substringToIndex:inputRetinaImagePath.length - 7] stringByAppendingString:@".png"]; 

    NSLog([@"Normal version file path: " stringByAppendingString:outputFilePath]); 
    [data writeToFile:outputFilePath atomically: NO]; 
    return true; 
} 
+0

यहाँ एक समाधान है कि * नहीं होगा * काम है का उपयोग संशोधित।ऐसा लगता था कि आपने यह कैसे किया, लेकिन यह हिम तेंदुए के बाद से हटा दिया गया है और शेर के रूप में काम नहीं करता है। –

+0

क्या आप इसे एक छोटे से आय में नहीं खींच सकते हैं? या संकेत के रूप में एक NSAffineTransform पास? –

+0

@RamyAlZuhouri: ऐसा लगता है कि एप्लिकेशन छवि के संकल्प को कम करने और परिणाम को बचाने के लिए, 2x पर संपत्ति बनाने और 1x संपत्तियों का उत्पादन करने के लिए है। –

उत्तर

10

आप एक NSImage के आकार विशेषता के बहुत सावधान रहना होगा। यह जरूरी bitmapRepresentation के पिक्सेल आयाम का उल्लेख नहीं है, यह इसी तरह, उदाहरण के लिए दिखाया गया है आकार का उल्लेख कर सकते हैं। एक NSImage विभिन्न उत्पादन आकार में उपयोग के लिए bitmapRepresentations के एक नंबर हो सकता है।

, एक NSImage के आकार विशेषता को बदलने के लिए कुछ भी नहीं bitmapRepresentations को बदलने के लिए करता है

तो क्या हुआ आपको ऐसा करने की ज़रूरत है, जिसे आप अपनी आउटपुट छवि चाहते हैं, और फिर उस आकार पर एक नई छवि खींचें, जिसका उपयोग बिटमैप स्रोत एनएसआईमेज से प्रस्तुत करना है।

यह आकार प्राप्त करना इस बात पर निर्भर करता है कि आपने अपनी इनपुट छवि कैसे प्राप्त की है और आप इसके बारे में क्या जानते हैं। उदाहरण के लिए, यदि आप विश्वास है अपने इनपुट छवि आप (NSImage पर एक वर्ग के रूप में) बात के इस प्रकार का उपयोग कर सकते केवल एक bitmapImageRep है कि

- (NSSize) pixelSize 
{ 
    NSBitmapImageRep* bitmap = [[self representations] objectAtIndex:0]; 
    return NSMakeSize(bitmap.pixelsWide,bitmap.pixelsHigh); 
} 

भले ही आप bitmapImageReps की एक संख्या है, पहले एक होना चाहिए सबसे बड़ा, और यदि वह आकार है जिस पर आपकी रेटिना छवि बनाई गई थी, तो यह रेटिना आकार होना चाहिए जिसके बाद आप हैं।

जब आप अपने अंतिम आकार बाहर काम किया है, तो आप छवि बना सकते हैं:

- (NSImage*) resizeImage:(NSImage*)sourceImage size:(NSSize)size 
{ 

    NSRect targetFrame = NSMakeRect(0, 0, size.width, size.height);  
    NSImage* targetImage = nil; 
    NSImageRep *sourceImageRep = 
    [sourceImage bestRepresentationForRect:targetFrame 
            context:nil 
            hints:nil]; 

    targetImage = [[NSImage alloc] initWithSize:size]; 

    [targetImage lockFocus]; 
    [sourceImageRep drawInRect: targetFrame]; 
    [targetImage unlockFocus]; 

return targetImage; 

}

अद्यतन

यहाँ की एक अधिक विस्तृत संस्करण है एक पिक्सेल-आकार- एनएसआईमेज पर श्रेणी प्राप्त करना ... आइए छवि के बारे में कुछ भी नहीं मानें, इसमें कितनी छवियां हैं, चाहे कोई बिटमैप इमेज रेप्स ... यह सबसे बड़ा पिक्सेल आयाम वापस कर देगा I टी मिल सकता है यदि यह bitMapImageRep पिक्सेल आयाम नहीं ढूंढ पाता है तो यह जो कुछ भी प्राप्त कर सकता है उसका उपयोग करेगा, जो अधिकतर बॉक्स आयामों को बाध्य करेगा (ईपीएस और पीडीएफ द्वारा उपयोग किया जाता है)।

NSImage + PixelSize.h

#import <Cocoa/Cocoa.h> 
#import <QuartzCore/QuartzCore.h> 

@interface NSImage (PixelSize) 

- (NSInteger) pixelsWide; 
- (NSInteger) pixelsHigh; 
- (NSSize) pixelSize; 

@end 

NSImage + PixelSize.m

#import "NSImage+PixelSize.h" 

@implementation NSImage (Extensions) 

- (NSInteger) pixelsWide 
{ 
    /* 
    returns the pixel width of NSImage. 
    Selects the largest bitmapRep by preference 
    If there is no bitmapRep returns largest size reported by any imageRep. 
    */ 
    NSInteger result = 0; 
    NSInteger bitmapResult = 0; 

    for (NSImageRep* imageRep in [self representations]) { 
     if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { 
      if (imageRep.pixelsWide > bitmapResult) 
       bitmapResult = imageRep.pixelsWide; 
     } else { 
      if (imageRep.pixelsWide > result) 
       result = imageRep.pixelsWide; 
     } 
    } 
    if (bitmapResult) result = bitmapResult; 
    return result; 

} 

- (NSInteger) pixelsHigh 
{ 
    /* 
    returns the pixel height of NSImage. 
    Selects the largest bitmapRep by preference 
    If there is no bitmapRep returns largest size reported by any imageRep. 
    */ 
    NSInteger result = 0; 
    NSInteger bitmapResult = 0; 

    for (NSImageRep* imageRep in [self representations]) { 
     if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { 
      if (imageRep.pixelsHigh > bitmapResult) 
       bitmapResult = imageRep.pixelsHigh; 
     } else { 
      if (imageRep.pixelsHigh > result) 
       result = imageRep.pixelsHigh; 
     } 
    } 
    if (bitmapResult) result = bitmapResult; 
    return result; 
} 

- (NSSize) pixelSize 
{ 
    return NSMakeSize(self.pixelsWide,self.pixelsHigh); 
} 

@end 

आप अपने वर्तमान फ़ाइल में #import "NSImage+PixelSize.h" यह सुलभ बनाने के लिए होगा।

इस छवि श्रेणी और आकार बदलने के साथ

: विधि, आप इस प्रकार आपके विधि को संशोधित होगा:

//size.width = inputRetinaImage.size.width*0.5; 
//size.height = inputRetinaImage.size.height*0.5; 
size.width = inputRetinaImage.pixelsWide*0.5; 
size.height = inputRetinaImage.pixelsHigh*0.5; 

//[inputRetinaImage setSize:size]; 
NSImage* outputImage = [self resizeImage:inputRetinaImage size:size]; 

//NSBitmapImageRep *imgRep = [[inputRetinaImage representations] objectAtIndex: 0]; 
NSBitmapImageRep *imgRep = [[outputImage representations] objectAtIndex: 0]; 

कि आप (परंतुक: मैं अपने कोड पर यह परीक्षण नहीं किया) के लिए चाहिए ठीक बातें

`setScalesWhenResized:`
+0

क्यों नहीं, सभी तीन स्थानों में 'सर्वश्रेष्ठ प्रस्तुतिकरण के लिए संदर्भ: संदर्भ: संकेत:' का उपयोग क्यों नहीं करें? –

+1

मुझे लगता है कि यह सवाल पूछे जा रहा है ... BestReresentationForRect: सुझाव देता है कि हम अंतिम आकार के बारे में जानते हैं जो हम बाद में हैं - जो इस मामले में हम नहीं कर सकते हैं, हम रेटिना के आकार को कम करने के लिए देख रहे हैं ... बिटमैप। एनएसआईमेज एक साथ कैसे लटकता है, यह जानने में एक अभ्यास के रूप में, यह समझना बुरा नहीं है कि विभिन्न छवियाँ वास्तव में एक-दूसरे से कैसे संबंधित हैं? – foundry

+0

यह परिपत्र नहीं है क्योंकि आय स्रोत छवि के उपयोगकर्ता स्थान में है। यदि आप पूरी छवि चाहते हैं, तो आयत में किसी भी प्रस्तुति के पिक्सेल संकल्प (या इसकी कमी) के बावजूद, या वांछित आकार के आकार के बावजूद आयत ('NSRect) {NSZeroPoint, image.size} 'है, संकल्प। मैं सहमत हूं कि प्रतिनिधि की प्रकृति को समझना अच्छा है; हालांकि, पहले प्रतिनिधि को पकड़कर और यह मानते हुए कि यह वही होगा जो आप चाहते हैं कि वह अंत तक अच्छा न हो। –

2

मैं स्क्रिप्ट मैं आप के लिए अपनी छवियों downscale करने के लिए :)

-(BOOL)createNormalImage:(NSString*)inputRetinaImagePath { 

    NSImage *inputRetinaImage = [[NSImage alloc] initWithContentsOfFile:inputRetinaImagePath]; 

    //determine new size 
    NSBitmapImageRep* bitmapImageRep = [[inputRetinaImage representations] objectAtIndex:0]; 
    NSSize size = NSMakeSize(bitmapImageRep.pixelsWide * 0.5,bitmapImageRep.pixelsHigh * 0.5); 

    NSLog(@"size = %@", NSStringFromSize(size)); 

    //get CGImageRef 
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)[inputRetinaImage TIFFRepresentation], NULL); 
    CGImageRef oldImageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL); 
    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(oldImageRef); 
    if (alphaInfo == kCGImageAlphaNone) alphaInfo = kCGImageAlphaNoneSkipLast; 

    // Build a bitmap context 
    CGContextRef bitmap = CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, CGImageGetColorSpace(oldImageRef), alphaInfo); 

    // Draw into the context, this scales the image 
    CGContextDrawImage(bitmap, CGRectMake(0, 0, size.width, size.height), oldImageRef); 

    // Get an image from the context 
    CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); 

    //this does not work in my test. 
    NSString *outputFilePath = [[inputRetinaImagePath substringToIndex:inputRetinaImagePath.length - 7] stringByAppendingString:@".png"]; 

    //but this does! 
    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString* docsDirectory = [paths objectAtIndex:0]; 
    NSString *newfileName = [docsDirectory stringByAppendingFormat:@"/%@", [outputFilePath lastPathComponent]]; 

    CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:newfileName]; 
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL); 
    CGImageDestinationAddImage(destination, newImageRef, nil); 

    if (!CGImageDestinationFinalize(destination)) { 
     NSLog(@"Failed to write image to %@", newfileName); 
    } 

    CFRelease(destination); 

    return true; 
}