How to save PNG file from NSImage (retina issues)

后端 未结 6 985
情话喂你
情话喂你 2020-11-29 01:37

I\'m doing some operations on images and after I\'m done, I want to save the image as PNG on disk. I\'m doing the following:

+ (void)saveImage:(NSImage *)ima         


        
6条回答
  •  猫巷女王i
    2020-11-29 02:23

    NSImage is resolution aware and uses a HiDPI graphics context when you lockFocus on a system with retina screen.
    The image dimensions you pass to your NSBitmapImageRep initializer are in points (not pixels). An 150.0 point-wide image therefore uses 300 horizontal pixels in a @2x context.

    You could use convertRectToBacking: or backingScaleFactor: to compensate for the @2x context. (I didn't try that), or you can use the following NSImage category, that creates a drawing context with explicit pixel dimensions:

    @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
    

提交回复
热议问题