【问题标题】:Turning an NSImage* into a CGImageRef?将 NSImage* 变成 CGImageRef?
【发布时间】:2010-03-30 19:27:19
【问题描述】:

在 10.5 中是否有一种简单的方法可以做到这一点?

在 10.6 中我可以使用 nsImage CGImageForProposedRect:NULL 上下文:NULL 提示:NULL

如果我不使用 1b 黑白图像(如 Group 4 TIFF),我可以使用位图,但 cgbitmaps 似乎不喜欢这种设置...有没有通用的方法?

我需要这样做,因为我有一个似乎只想添加 CGImages 的 IKImageView,但我所拥有的只是 NSImages。目前,我正在使用一个私有的 setImage:(NSImage*) 方法,我真的不想使用它......

【问题讨论】:

  • 你知道我在哪里可以获得如何使用 CGImageForProposedRect 的示例:NULL 上下文:NULL 提示:NULL。我为第一个参数提供了一个 NSRect,但我得到了一个类型不匹配。
  • 我不知道我从来没有尝试过除了 NULL 之外的任何东西......可能是 CGRect 而不是 NSRect?

标签: objective-c cocoa core-graphics nsimage cgimage


【解决方案1】:

this page找到以下解决方案:

NSImage* someImage;
// create the image somehow, load from file, draw into it...
CGImageSourceRef source;

source = CGImageSourceCreateWithData((CFDataRef)[someImage TIFFRepresentation], NULL);
CGImageRef maskRef =  CGImageSourceCreateImageAtIndex(source, 0, NULL);

所有方法似乎都是 10.4+,所以你应该没问题。

【讨论】:

  • 是的,但不要拨打TIFFRepresentation 数百次。根据NSImage,它最终会在内存中创建完整的、未压缩的图像数据副本。
  • 有趣。我会试试的,然后告诉你。
  • 这在性能和可预测性方面不如 Peter 的解决方案好。如果图像有多种表示形式(例如 16x16 版本和 128x128 版本),你会这样得到吗?未定义。
【解决方案2】:

[这是很长的路要走。仅当您仍支持旧版 OS X 时才应执行此操作。如果您需要 10.6 或更高版本,请改用just use the CGImage method。]

  1. Create a CGBitmapContext.
  2. Create an NSGraphicsContext for the bitmap context.
  3. Set the graphics context as the current context.
  4. Draw the image.
  5. Create the CGImage from the contents of the bitmap context.
  6. 释放位图上下文。

【讨论】:

  • 我已经尝试过了,它似乎不适用于 1 位黑白图像(mac 出于某种原因真的不喜欢处理 CCITT TIFF ......)或失去分辨率...由于我有一个 NSImage,我不确定我是否真的可以找到分辨率来弄清楚如何制作更好的图形上下文...
  • 查看图像的representations 数组。其中之一应该是位图图像代表。您可以询问该对象的像素大小(而不是点),以及其他与栅格相关的事实。
  • Peter,您是我在 SO 上钦佩和信任的成员。感谢您分享的所有知识和经验,以及您所提供的全面性。
  • @MikeyWard:不客气,谢谢你的好话。
  • 而不是链接,你能把它转换成代码吗?谢谢。
【解决方案3】:

对于 Snow Leopard,您只需 ask the image to create a CGImage for you,通过向 NSImage 发送 CGImageForProposedRect:context:hints: 消息即可。

【讨论】:

    【解决方案4】:

    这里有一个更详细的使用- CGImageForProposedRect:context:hints:的答案:

    NSImage *image = [NSImage imageNamed:@"image.jpg"];
    
    NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);
    
    CGImageRef cgImage = [image CGImageForProposedRect:&imageRect context:NULL hints:nil];
    

    【讨论】:

      【解决方案5】:

      刚刚使用CGImageForProposedRect:context:hints:...

      NSImage *image; // an image
      NSGraphicsContext *context = [NSGraphicsContext currentContext];
      CGRect imageCGRect = CGRectMake(0, 0, image.size.width, image.size.height);
      NSRect imageRect = NSRectFromCGRect(imageCGRect);
      CGImageRef imageRef = [image CGImageForProposedRect:&imageRect context:context hints:nil];
      

      【讨论】:

      • 您不需要此示例中所示的图形上下文。这是一个可选参数。
      【解决方案6】:

      自 2021 年起,CALayers contents 可以直接使用 NSImage 进行馈送,但您仍可能收到
      [Utility] unsupported surface format: LA08 警告。 经过几天的研究和测试,我发现如果您使用 backingLayer(又名 CALayer)创建了一个 NSView 并仅使用 NSImage 来提供其 contents,则会触发此警告。仅此一项问题不大。但是如果你尝试通过[self.layer renderInContext:ctx]进行渲染,每次渲染都会再次触发警告。

      为了简单起见,我创建了一个 NSImage 扩展来解决这个问题..

      @interface NSImage (LA08FIXExtension)
      -(id)CGImageRefID;
      @end
      
      @implementation NSImage (LA08FIXExtension)
      
      -(id)CGImageRefID {
          NSSize size = [self size];
          NSRect rect = NSMakeRect(0, 0, size.width, size.height);
          CGImageRef ref = [self CGImageForProposedRect:&rect context:[NSGraphicsContext currentContext] hints:NULL];
          return (__bridge id)ref;
      }
      
      @end
      

      看看它是如何不直接返回一个 CGImageRef 而是一个桥接到id..!这样就行了。

      现在你可以像这样使用它了..

      CALayer *somelayer = [CALayer layer];
      somelayer.frame = ... 
      somelayer.contents = [NSImage imageWithName:@"SomeImage"].CGImageRefID;
      

      PS:发布她是因为如果你也遇到这个问题,谷歌无论如何都会引导你到这个答案线程,以上所有答案都启发了我进行这个修复。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多