NSImage to NSBitmapImageRep

半城伤御伤魂 提交于 2019-12-03 17:13:44

问题


How to convert NSImage to NSBitmapImageRep? I have code:

- (NSBitmapImageRep *)bitmapImageRepresentation
{
    NSBitmapImageRep *ret = (NSBitmapImageRep *)[self representations];

    if(![ret isKindOfClass:[NSBitmapImageRep class]])
    {
        ret = nil;
        for(NSBitmapImageRep *rep in [self representations])
            if([rep isKindOfClass:[NSBitmapImageRep class]])
            {
                ret = rep;
                break;
            }
    }

    if(ret == nil)
    {
        NSSize size = [self size];

        size_t width         = size.width;
        size_t height        = size.height;
        size_t bitsPerComp   = 32;
        size_t bytesPerPixel = (bitsPerComp / CHAR_BIT) * 4;
        size_t bytesPerRow   = bytesPerPixel * width;
        size_t totalBytes    = height * bytesPerRow;

        NSMutableData *data = [NSMutableData dataWithBytesNoCopy:calloc(totalBytes, 1) length:totalBytes freeWhenDone:YES];

        CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

        CGContextRef ctx = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComp, bytesPerRow, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGBitmapFloatComponents | kCGImageAlphaPremultipliedLast);

        if(ctx != NULL)
        {
            [NSGraphicsContext saveGraphicsState];
            [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[self isFlipped]]];

            [self drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];

            [NSGraphicsContext restoreGraphicsState];

            CGImageRef img = CGBitmapContextCreateImage(ctx);

            ret = [[NSBitmapImageRep alloc] initWithCGImage:img];
            [self addRepresentation:ret];

            CFRelease(img);
            CFRelease(space);

            CGContextRelease(ctx);
        }
    }


    return ret;
}

It works, but it causes memory leaks. At least when I am using it with ARC. Using initWithData:[nsimagename TIFFRepresentation] it not working correctly. Some images`s representations are not good. I think it depends on format and colorspace of image. Is there any other ways to achieve that?


Result with mrwalker suggested solution:

Original image:

Converted to bitmapimagerep and back to image 1 time:

Converted to bitmapimagerep and back to image 3 times:

As you see image gets darker every time after converting to NSBitmapImageRep


回答1:


You could try this method adapted from Mike Ash's "Obtaining and Interpreting Image Data" blog post:

- (NSBitmapImageRep *)bitmapImageRepresentation {
  int width = [self size].width;
  int height = [self size].height;

  if(width < 1 || height < 1)
      return nil;

  NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
                           initWithBitmapDataPlanes: NULL
                           pixelsWide: width
                           pixelsHigh: height
                           bitsPerSample: 8
                           samplesPerPixel: 4
                           hasAlpha: YES
                           isPlanar: NO
                           colorSpaceName: NSDeviceRGBColorSpace
                           bytesPerRow: width * 4
                           bitsPerPixel: 32];

  NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep: rep];
  [NSGraphicsContext saveGraphicsState];
  [NSGraphicsContext setCurrentContext: ctx];  
  [self drawAtPoint: NSZeroPoint fromRect: NSZeroRect operation: NSCompositeCopy fraction: 1.0];
  [ctx flushGraphics];
  [NSGraphicsContext restoreGraphicsState];

  return [rep autorelease];
}



回答2:


@Julius: Your code is way too complicated and contains several bugs. I will make a correction for only the first lines:

- (NSBitmapImageRep *)bitmapImageRepresentation
{
   for( NSImageRep *rep in [self representations] )
      if( [rep isKindOfClass:[NSBitmapImageRep class]] ) return rep;
   return nil;
}

This will extract the first NSBitmapImageRep if it is member in the representations or will return nil, if there is no NSBitmapImageRep. I'll give you another solution which will always work whatever NSImageReps are in the representations: NSBitmapImageRep, NSPDFImageRep or NSCGImageSnapshotRep or ...

- (NSBitmapImageRep *)bitmapImageRepresentation
{
   CGImageRef CGImage = [self CGImageForProposedRect:nil context:nil hints:nil];
   return [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];
}

Or to avoid subclassing of NSImage you may write:

NSImage *img = [[[NSImage alloc] initWithContentsOfFile:filename] autorelease];
CGImageRef CGImage = [img CGImageForProposedRect:nil context:nil hints:nil];
NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];

This will only return a single NSBitmapImageRep which maybe not good enough if the image contains more than one representation (e.g. a lot of NSBitmapImageReps from TIFF files). But adding some code is straightforward.




回答3:


Maybe late to the party, but this is the Swift 3 version from the @mrwalker response:

extension NSImage {
    func bitmapImageRepresentation(colorSpaceName: String) -> NSBitmapImageRep? {
        let width = self.size.width
        let height = self.size.height

        if width < 1 || height < 1 {
            return nil
        }

        if let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(width), pixelsHigh: Int(height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: colorSpaceName, bytesPerRow: Int(width) * 4, bitsPerPixel: 32)
        {
            let ctx = NSGraphicsContext.init(bitmapImageRep: rep)
            NSGraphicsContext.saveGraphicsState()
            NSGraphicsContext.setCurrent(ctx)
            self.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
            ctx?.flushGraphics()
            NSGraphicsContext.restoreGraphicsState()
            return rep
        }
        return nil
    }
}


来源:https://stackoverflow.com/questions/12896831/nsimage-to-nsbitmapimagerep

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!