2012-10-02 8 views
8

Opracowuję szybką aplikację, w której mam metodę, która powinna przeskalować obraz @ 2x do zwykłego. Problemem jest to, że nie ma :(NSImage nie skaluje się

dlaczego?

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

Oto rozwiązanie, które nie będzie * * praca: 'setScalesWhenResized:'.Kiedyś tak to zrobiłeś, ale jest przestarzałe od Snow Leopard i nie działa tak jak Lion. –

+0

Nie możesz po prostu narysować go w mniejszej skali? Lub przekazać NSAffineTransform jako wskazówkę? –

+0

@RamyAlZuhouri: Wygląda na to, że aplikacja ma na celu obniżenie rozdzielczości obrazu i zapisanie wyniku, utworzenie zasobów przy 2x i wygenerowanie 1x zasobów z tego samego. –

Odpowiedz

10

Musisz być bardzo ostrożny atrybut rozmiaru NSImage. To niekoniecznie odnoszą się do wymiarów w pikselach na bitmapRepresentation za to może odnosić się do wyświetlanej wielkości np. NSImage może mieć szereg bitmapRepresentations do zastosowania w różnych wielkościach wyjściowych.

Podobnie, zmieniając atrybut rozmiaru NSImage nie robi nic, aby zmienić bitmapRepresentations

więc co musisz obliczyć rozmiar, który ma być obrazem wyjściowym, a następnie narysować nowy obraz w tym rozmiarze za pomocą bitmapReprezentacja ze źródła NSImage.

Uzyskanie tego rozmiaru zależy od tego, w jaki sposób uzyskałeś obraz wejściowy i co o nim wiesz. Na przykład, jeśli jesteś przekonany, że obraz wejściowy ma tylko jeden bitmapImageRep można użyć tego typu rzeczy (jako kategoria na NSImage)

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

Nawet jeśli mają szereg bitmapImageReps, pierwszy powinien być największy, a jeśli jest to rozmiar, w którym został utworzony twój obraz siatkówki, powinien to być rozmiar siatkówki, którego szukasz.

Po wypracowaliśmy swój ostateczny rozmiar, można zrobić obraz:

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

}

aktualizacji

Tutaj jest bardziej skomplikowana wersja piksel-size- uzyskanie kategorii na NSImage ... załóżmy, że nie ma nic o obrazie, ile ma on imageReps, czy ma on dowolny bitmapImageReps ... to zwróci największe wymiary piksela i t może znaleźć. Jeśli nie będzie w stanie znaleźć pikseli w pikselach bitmapImageRep, użyje tego, co jeszcze może uzyskać, co najprawdopodobniej będzie wymiarami obwiedni (używanymi przez eps i 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 

można byłoby #import "NSImage+PixelSize.h" w bieżącym pliku, aby go udostępnić.

z tą kategorią obrazu i zmiany rozmiaru: metoda, by zmodyfikować metodę tak:

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

To powinien rzeczy poprawek dla Ciebie (zastrzeżenie: nie testowałem go na kodzie)

+0

Dlaczego nie używać 'bestRepresentationForRect: context: hints:' we wszystkich trzech miejscach? –

+1

Myślę, że może to być pytanie ... BestRepresentationForRect: sugeruje, że znamy ostateczny rozmiar, którego szukamy - w tym przypadku nie, chcemy zmniejszyć o połowę rozmiar siatkówki ... bitmapy. Również jako ćwiczenie w uczeniu się, jak NSImage się trzyma, nie jest złym pomysłem, aby zrozumieć, w jaki sposób różne imageReps rzeczywiście odnoszą się do siebie nawzajem? – foundry

+0

Nie jest to cykliczny, ponieważ rect znajduje się w przestrzeni użytkownika obrazu źródłowego. Jeśli chcesz cały obraz, to rect to '(NSRect) {NSZeroPoint, image.size}', niezależnie od rozdzielczości pikseli (lub ich braku) dowolnej reprezentacji obrazu lub wymaganego skalowanego rozmiaru lub rozkład. Zgadzam się, że zrozumienie charakteru powtórzeń jest dobre; jednak chwytanie pierwszego przedstawiciela i zakładanie, że będzie to, czego chcesz, nie jest dobrym środkiem do tego celu. –

2

zmodyfikowałem skrypt używam dół skali moje obrazy dla ciebie :)

-(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; 
} 
Powiązane problemy