2012-10-02 75 views
8

我正在开发一个快速应用程序,其中我有一个方法应该将@ 2x图像重新缩放为常规应用程序。问题是,它不会:(NSImage不能缩放

为什么?

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

下面是* A解决方案将无法工作*脚本:'setScalesWhenResized:'。过去你是如何做到这一点的,但自从Snow Leopard以来它就被弃用了,并且不能像狮子那样工作。 –

+0

难道你不能只用一个较小的矩形来绘制它吗?或者传递一个NSAffineTransform作为提示? –

+0

@RamyAlZuhouri:听起来应用程序的目的是降低图像的分辨率并保存结果,以创建2倍的资产并生成1倍的资产。 –

回答

10

你必须非常警惕的NSImage中的大小属性,它并不一定是指bitmapRepresentation的像素尺寸,它可以参考的显示尺寸为例,一个NSImage中可能有许多bitmapRepresentations的在不同输出大小的使用。

同样,改变NSImage中的大小属性并没有改变bitmapRepresentations

那么什么你需要做的是制定出你想要的输出图像的大小,然后使用源NSImage的bitmapRepresentation绘制一个新的图像。

获取该大小取决于您如何获得输入图像以及您了解的信息。例如,如果你有信心,你的输入图像只有一个bitmapImageRep你可以使用这种类型的东西(如在NSImage中一个类别)

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

即使你有一些bitmapImageReps的,第一个应该是最大的一个,如果这是您的Retina图像创建的大小,则应该是您之后的Retina大小。

当你算出你的最终大小,可以使图像:

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

}

更新

这里是一个更复杂的版本,像素大小 - 在NSImage上获取类别...让我们假设没有关于图像,它有多少imageReps,它是否有任何 bitmapImageReps ...这将返回最大的像素尺寸i吨可以找到。如果找不到bitMapImageRep像素尺寸,它将使用任何可以获得的值,这很可能是包围盒尺寸(由eps和pdf使用)。

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]; 

应该解决的事情,你(前提:我没有测试它在你的代码)

+0

为什么不在所有三个地方使用'bestRepresentationForRect:context:hints:'? –

+1

我认为这可能是乞讨的问题... ... BestRepresentationForRect:建议我们知道最终的大小 - 在这种情况下,我们可能不会,我们正在寻找减少视网膜大小...位图。另外作为学习NSImage如何挂在一起的练习,掌握各个imageReps如何实际相互关联并不是一个坏主意? – foundry

+0

由于rect位于源图像的用户空间中,因此不是循环的。如果您想要整个图像,则无论图像中任何表示的像素分辨率(或缺少),还是所需的缩放大小,或者所需的缩放大小,矩形都是(NSRect){NSZeroPoint,image.size}解析度。我同意,了解代表的本质是好的;然而,抓住第一个代表并假设它将成为你想要的并不是达到这个目的的好手段。 –

2

我修改我用它来缩减我的画面,供各位:)

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