19

이미지 작업을하고 있습니다. 끝나면 이미지를 디스크에 PNG로 저장하려고합니다. 나는 다음과 같은 일을 해요 : 나는 NSBitmapImageRep 개체를 인쇄하면이 코드가 작동NSImage (망막 문제)에서 PNG 파일을 저장하는 방법

+ (void)saveImage:(NSImage *)image atPath:(NSString *)path { 

    [image lockFocus] ; 
    NSBitmapImageRep *imageRepresentation = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0.0, 0.0, image.size.width, image.size.height)] ; 
    [image unlockFocus] ; 

    NSData *data = [imageRepresentation representationUsingType:NSPNGFileType properties:nil]; 
    [data writeToFile:path atomically:YES]; 
} 

하지만, 문제는 망막 맥 함께, 내가 다른 크기와 픽셀하는 구형을 얻을 내 이미지가 디스크에 저장 될 때,

imageRepresentation.pixelsWide = image.size.width; 
imageRepresentation.pixelsHigh = image.size.height; 

내가 얻을이 시간 :

$0 = 0x0000000100413890 NSBitmapImageRep 0x100413890 Size={300, 300} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=8 BPP=32 Pixels=600x600 Alpha=YES Planar=NO Format=0 CurrentBacking=<CGImageRef: 0x100414830> 

은 내가 원래 크기를 유지하려면로서, 망막 규모에 대해 조심하지 픽셀 크기를 강제로 묶여 : 그것은 두 배 크기입니다 적당한 크기 나는 NSBitmapImageRep 개체를 인쇄,하지만 난 내 파일을 저장할 때 나는 여전히 같은 문제를 얻을 때 :

$0 = 0x0000000100413890 NSBitmapImageRep 0x100413890 Size={300, 300} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=8 BPP=32 Pixels=300x300 Alpha=YES Planar=NO Format=0 CurrentBacking=<CGImageRef: 0x100414830> 

어떤 생각이 어떻게이 문제를 해결하고, 원래의 픽셀 크기를 유지하기를?

답변

35

과에 이미지 파일로 저장할 파일 시스템은 결코을 사용하십시오 lockFocus! lockFocus은 화면을 표시하고 다른 것은 표시하지 않기로 결정된 새 이미지를 만듭니다. 따라서 lockFocus은 화면의 속성을 사용합니다 : 의 경우 72 dpi, 의 경우 14424 dpi, 망막의 화면을 사용합니다. 원하는 코드에 대해 다음 코드를 제안합니다.

+ (void)saveImage:(NSImage *)image atPath:(NSString *)path { 

    CGImageRef cgRef = [image CGImageForProposedRect:NULL 
              context:nil 
               hints:nil]; 
    NSBitmapImageRep *newRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef]; 
    [newRep setSize:[image size]]; // if you want the same resolution 
    NSData *pngData = [newRep representationUsingType:NSPNGFileType properties:nil]; 
    [pngData writeToFile:path atomically:YES]; 
    [newRep autorelease]; 
} 
+2

'- [NSBitmapImageRep setSize :]'는 10.10 이후에만 사용 가능한 것으로 보입니다. 어째서 매버릭스에서 코드를 사용해 보았을 때 이미지의 크기가 조정되지 않는 이유는 무엇입니까? 예외는 발생하지 않지만 ... 어떤 크기로 전달 되든 원래 크기와 동일한 크기의 이미지를 얻고 있습니다. –

+0

@ NicolasMiari'newRep'의 크기가 10.9이지만 10.10에서 실행되고 있어야하지만, 디스크에 기록 된 파일에는 여전히 2x 이미지가 포함되어 있습니다. 혹시 해결책을 찾았습니까? – Dov

+0

네, 아래 Weichsel의 대답이 저에게 효과적이었습니다. –

14

NSImage은 해상도 인식이며 망막 화면이있는 시스템에서 lockFocus 일 때 HiDPI 그래픽 컨텍스트를 사용합니다.
NSBitmapImageRep 이니셜 라이저에 전달하는 이미지 크기는 픽셀 단위가 아닌 포인트 수입니다. 따라서 150.0 포인트 너비의 이미지는 @ 2x 컨텍스트에서 300 개의 가로 픽셀을 사용합니다.

@ 2x 컨텍스트를 보완하려면 convertRectToBacking: 또는 backingScaleFactor:을 사용할 수 있습니다. (나는 그것을 시도하지 않았다), 또는 당신은 명시 적 픽셀 크기와 드로잉 컨텍스트 만드는 다음 NSImage 카테고리, 사용할 수 있습니다 : 당신이 NSImage이있는 경우

@interface NSImage (SSWPNGAdditions) 

- (BOOL)writePNGToURL:(NSURL*)URL outputSizeInPixels:(NSSize)outputSizePx error:(NSError*__autoreleasing*)error; 

@end 

@implementation NSImage (SSWPNGAdditions) 

- (BOOL)writePNGToURL:(NSURL*)URL outputSizeInPixels:(NSSize)outputSizePx error:(NSError*__autoreleasing*)error 
{ 
    BOOL result = YES; 
    NSImage* scalingImage = [NSImage imageWithSize:[self size] flipped:NO drawingHandler:^BOOL(NSRect dstRect) { 
     [self drawAtPoint:NSMakePoint(0.0, 0.0) fromRect:dstRect operation:NSCompositeSourceOver fraction:1.0]; 
     return YES; 
    }]; 
    NSRect proposedRect = NSMakeRect(0.0, 0.0, outputSizePx.width, outputSizePx.height); 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 
    CGContextRef cgContext = CGBitmapContextCreate(NULL, proposedRect.size.width, proposedRect.size.height, 8, 4*proposedRect.size.width, colorSpace, kCGBitmapByteOrderDefault|kCGImageAlphaPremultipliedLast); 
    CGColorSpaceRelease(colorSpace); 
    NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:NO]; 
    CGContextRelease(cgContext); 
    CGImageRef cgImage = [scalingImage CGImageForProposedRect:&proposedRect context:context hints:nil]; 
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)(URL), kUTTypePNG, 1, NULL); 
    CGImageDestinationAddImage(destination, cgImage, nil); 
    if(!CGImageDestinationFinalize(destination)) 
    { 
     NSDictionary* details = @{NSLocalizedDescriptionKey:@"Error writing PNG image"}; 
     [details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey]; 
     *error = [NSError errorWithDomain:@"SSWPNGAdditionsErrorDomain" code:10 userInfo:details]; 
     result = NO; 
    } 
    CFRelease(destination); 
    return result; 
} 

@end 
+0

여러 솔루션을 시도했습니다 (여기서 허용되는 대답 포함). 이것이 내가 해보 려던 유일한 해결책이다. 감사! – EsbenB

+0

당신의 솔루션을 구현하고 있습니다. "isFlipped는 더 이상 사용되지 않습니다. OS X 10.6에서는 처음 사용되지 않습니다."라는 경고 메시지가 나타납니다. 경고를 무시하거나 전화를 더 잘 끊어야합니까? –

+0

또한 열거 형 'enum CGImageAlphaInfo'에서 다른 열거 형 'CGBitmapInfo'(일명 'enum CGBitmapInfo') "로 암시 적 변환. 이것은 더 심각한 경고로 보인다. 나는이 두 enum의 정의를 확인했는데, 그것들은 완전히 다릅니다. 그러나'CGBitmapInfo'에는 '미리 곱셈 된 알파'에 대한 상수가 없습니다. –

4

이 코드는 웹에서 발견되었으며 망막에서 작동합니다. 여기에 붙여 넣기, 희망은 누군가를 도울 수 있습니다.

NSImage *computerImage = [NSImage imageNamed:NSImageNameComputer]; 
NSInteger size = 256; 

NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] 
        initWithBitmapDataPlanes:NULL 
           pixelsWide:size 
           pixelsHigh:size 
          bitsPerSample:8 
          samplesPerPixel:4 
            hasAlpha:YES 
            isPlanar:NO 
          colorSpaceName:NSCalibratedRGBColorSpace 
           bytesPerRow:0 
           bitsPerPixel:0]; 
[rep setSize:NSMakeSize(size, size)]; 

[NSGraphicsContext saveGraphicsState]; 
[NSGraphicsContext setCurrentContext:[NSGraphicsContext  graphicsContextWithBitmapImageRep:rep]]; 
[computerImage drawInRect:NSMakeRect(0, 0, size, size) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; 
[NSGraphicsContext restoreGraphicsState]; 

NSData *data = [rep representationUsingType:NSPNGFileType properties:nil]; 
+0

https://gist.github.com/mattstevens/4400775 1x 이미지로 출력하기 위해 망막 맥에서 NSImage 크기 조정 – flowers

+0

이것은 질문에 대한 직접적인 응답으로 보이지 않습니다 – abarisone

4

아무도이 스레드에서 우연히 발견하지 마십시오. 여기서 (방법 2 묘화 정보 + 오프 스크린 이미지를 처리하는 기록 포함 OS의 X에 대한 신속한

public func writeToFile(path: String, atomically: Bool = true) -> Bool{ 

    let bitmap = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(self.size.width), pixelsHigh: Int(self.size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)! 
    bitmap.size = self.size 

    NSGraphicsContext.saveGraphicsState() 

    NSGraphicsContext.setCurrentContext(NSGraphicsContext(bitmapImageRep: bitmap)) 
    self.drawAtPoint(CGPoint.zero, fromRect: NSRect.zero, operation: NSCompositingOperation.CompositeSourceOver, fraction: 1.0) 
    NSGraphicsContext.restoreGraphicsState() 

    if let imagePGNData = bitmap.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [NSImageCompressionFactor: 1.0]) { 
     return imagePGNData.writeToFile((path as NSString).stringByStandardizingPath, atomically: atomically) 
    } else { 
     return false 
    } 
} 
0

제 2 센트에 관계없이 장치의 1X 크기 (image.size)에 화상을 저장하는 작업을 수행 결함 용액 확실히); NSGraphicsContext.currentContextDrawingToScreen()을 사용하여 확인할 수 있습니다.

func createCGImage() -> CGImage? { 

    //method 1 
    let image = NSImage(size: NSSize(width: bounds.width, height: bounds.height), flipped: true, drawingHandler: { rect in 
     self.drawRect(self.bounds) 
     return true 
    }) 
    var rect = CGRectMake(0, 0, bounds.size.width, bounds.size.height) 
    return image.CGImageForProposedRect(&rect, context: bitmapContext(), hints: nil) 


    //method 2 
    if let pdfRep = NSPDFImageRep(data: dataWithPDFInsideRect(bounds)) { 
     return pdfRep.CGImageForProposedRect(&rect, context: bitmapContext(), hints: nil) 
    } 
    return nil 
} 

func PDFImageData(filter: QuartzFilter?) -> NSData? { 
    return dataWithPDFInsideRect(bounds) 
} 

func bitmapContext() -> NSGraphicsContext? { 
    var context : NSGraphicsContext? = nil 
    if let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil, 
             pixelsWide: Int(bounds.size.width), 
             pixelsHigh: Int(bounds.size.height), bitsPerSample: 8, 
             samplesPerPixel: 4, hasAlpha: true, isPlanar: false, 
             colorSpaceName: NSCalibratedRGBColorSpace, 
             bytesPerRow: Int(bounds.size.width) * 4, 
             bitsPerPixel: 32) { 
     imageRep.size = NSSize(width: bounds.size.width, height: bounds.size.height) 
     context = NSGraphicsContext(bitmapImageRep: imageRep) 
    } 
    return context 
} 

func writeImageData(view: MyView, destination: NSURL) { 
    if let dest = CGImageDestinationCreateWithURL(destination, imageUTType, 1, nil) { 
     let properties = imageProperties 
     let image = view.createCGImage()! 
     let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
     dispatch_async(queue) { 
      CGImageDestinationAddImage(dest, image, properties) 
      CGImageDestinationFinalize(dest) 
     } 
    } 
}