有没有办法将NSView包含子视图转换为NSImage?

时间:2014-12-18 18:59:31

标签: objective-c cocoa nsview nsimage

有没有办法将NSView包含多个背景颜色的子视图转换为NSImage? 示例代码非常棒

    NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[_collageView bounds]];
        [_collageView unlockFocus];
    //    NSData *exportedData = [rep representationUsingType:NSJPEGFileType properties:nil];
          NSData *exportedData = [rep representationUsingType:NSPNGFileType properties:nil];


        NSSavePanel *savepanel = [NSSavePanel savePanel];
    savepanel.title = @"Save chart";
    [savepanel setAllowedFileTypes:[NSArray arrayWithObject:@"png"]];
    [savepanel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result)
     {
         if (NSFileHandlingPanelOKButton == result)
         {
             NSURL* fileURL = [savepanel URL];
             if ([fileURL.pathExtension isEqualToString:@""])
                 fileURL = [fileURL URLByAppendingPathExtension:@"png"];

             [exportedData writeToURL:fileURL atomically:YES];
         }
     }];

我还使用以下代码

 [_collageView lockFocus];
    NSBitmapImageRep *bits = [[NSBitmapImageRep alloc]initWithFocusedViewRect: [_collageView bounds]];
    [_collageView unlockFocus];
    NSImage *image1 = [[NSImage alloc] init];
    [image1 addRepresentation: bits];
    [self.ImageView setImage:image1];

但没有工作

3 个答案:

答案 0 :(得分:2)

您的方法从Windows服务器复制位图。这是视图的呈现的内容。通常你不想这样做。

这是一种更好的方法来锁定NSImage上的焦点,-drawRect:构建图形上下文,然后使用// perhaps in a category of NSView - (void)drawRecursively { [self drawRect:self.bounds]; for (NSView *subview in self.subviews) { [subview drawRecursively]; } } 或您拥有的任何绘图方法绘制到该图像。您只需迭代它们即可添加子视图。

NSImage *image = [[NSImage alloc] initWithSize:theView.bounds.size];
[image lockFocus]; // Set-up the context for the image
[theView drawRecursively];
[image unlockFocus];

开始那个

{{1}}

在Safari中输入。

编辑:在转到子视图之前,您必须为它们执行转换。忘了。

答案 1 :(得分:0)

我实际上已经在屏幕外实现了视图层次结构的绘制。 即使对于所有视图的非常简单的视图层次结构,这也是非常重要的 子类NSControl并且 - (BOOL)isFlipped {return YES; }

这是该代码的一小部分,它可以让您了解这样做的痛苦:

- (void)drawRect:(NSRect)iDirtyBigRect
{
#ifdef DISABLE_PSEUDOVIEW
   debugRectsBeingDrawn();
   return;
#endif

   if ( !drawableShape )
   {
      if ( [[[self window] contentView] wantsLayer] )
      {
         CGRect cgRect = NSRectToCGRect([self bounds]);
         drawableShape = HIShapeCreateMutableWithRect( &cgRect );
      }
      else
      {
         DUMP( @"our superview should have set up our drawableShape!" );
         [self setNeedsDisplay:YES];
         return;
      }
   }
   else if ( iDirtyBigRect.size.width <= 0 )
   {
      // Our drawable shape is empty.
      // This can happen for several valid reasons:
      // 1) dirtyShape is fully masked by opaqueShape
      // 2) for some reason, we were called to obey needsDisplay when not needed
      DLog( @"nothing to draw %@", self );
      return; // must return, otherwise we risk drawing outside our bounds
   }

   //NSArray *hardSubviews = [self subviews];
   for ( NSView *pseudoSubview in pseudoSubviews )
   {
      if ( ![pseudoSubview isHidden] && 
          [pseudoSubview window] == offscreenWindow ) // only draw pseudo view if it's in offscreen window
      {
         NSRect rectToDraw = [pseudoSubview frame];
//         if ( rectToDraw.size.width == 0 )
//         {
//            DLog( @"clipped to superview %@", pseudoSubview );
//         }
         CGRect cgRect = NSRectToCGRect(rectToDraw);
         if ( HIShapeIntersectsRect(drawableShape, &cgRect) )
         {         
            // the magic: transform to subview coordinates
            NSAffineTransform* xform = [NSAffineTransform transform];

            [xform translateXBy:rectToDraw.origin.x yBy:rectToDraw.origin.y];
            if ( [pseudoSubview isFlipped] != [self isFlipped] )
            {
               if ( ![pseudoSubview isKindOfClass: [NSColorWell class]] )
               {
                  DUMP( @"hmmm flippedness different %d %d", [pseudoSubview isFlipped], [self isFlipped] );
               }
               [xform translateXBy:0.0 yBy:rectToDraw.size.height];
               [xform scaleXBy:1.0 yBy:-1.0];
            }
            [xform concat];

            HIMutableShapeRef newShape = HIShapeCreateMutableWithRect( &cgRect );
            HIShapeIntersect( newShape, drawableShape, newShape ); // clip to subview frame
            HIShapeOffset( newShape, -cgRect.origin.x, -cgRect.origin.y ); // translate to subview coords
            CGRect dirtyRect;
            HIShapeGetBounds(newShape, &dirtyRect);
//            if ( dirtyRect.size.width <= 0 )
//            {
//               DUMP( @"why?" );
//            }

            if ( [pseudoSubview isKindOfClass:[PseudoView class]] )
            {
               //DLog( @"drawing Pseudo %@ dirtyRect %@ ", pseudoSubview, NSStringFromRect(NSRectFromCGRect(dirtyRect)));

               PseudoView *pView = (PseudoView *)pseudoSubview;
               if ( pView->drawableShape )
               {
                  CFRelease( pView->drawableShape );
                  pView->drawableShape = NULL;
               }
               // create subview personal drawableShape from my drawable shape
               pView->drawableShape = newShape;
               if ( [pseudoSubview isOpaque] )
                  gDrawDirtyPixels += dirtyRect.size.width * dirtyRect.size.height;

               if ( dirtyRect.size.width > 0 )
                  [pseudoSubview drawRect: NSRectFromCGRect(dirtyRect)];

            }
            else
            {
               //DLog( @"drawing non-Pseudo %@ rectToDraw %@ ", pseudoSubview, NSStringFromRect( rectToDraw ));

               UInt64 t1 = CpuCycles();
               CFRelease( newShape );
               // sacrifice efficiency to avoid bugs...
               // always draw the entire view.
               [pseudoSubview drawRect:[pseudoSubview bounds]]; // NSRectFromCGRect(dirtyRect)]; // [pseudoSubview bounds]];
               UnitTestQuartz( [pseudoSubview bounds] );
               // NSLog( @"drawRect %@ %@ sUnitTestQuartzToggle %f\n -- superv %@\n -- self %@", pseudoSubview, NSStringFromRect(rectToDraw), sUnitTestQuartzToggle*100, [pseudoSubview superview],  self );
               UInt64 t2 = CpuCycles();
               int diff = (int)(t2-t1);
               gDrawControl += diff;
            }


            [xform invert]; // restore
            [xform concat];
         }
      }
   }

   //if ( [self isKindOfClass:[PseudoRootView class]] )
   //   [offscreenWindow setViewsNeedDisplay:NO];
}

答案 2 :(得分:0)

我可以使用以下代码解决我的问题

  // Setup the image to render
        NSRect imgRect = _collageView.frame;
        NSSize imgSize = imgRect.size;

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

        NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:rep];
        [NSGraphicsContext saveGraphicsState];
        [NSGraphicsContext setCurrentContext:context];
        // Render
        CGContextRef zCgContextRef = (CGContextRef) [context graphicsPort];
        [[_collageView layer] renderInContext:zCgContextRef];

        // Get the Data for the image
        NSData *exportedData = [rep representationUsingType:NSJPEGFileType properties:nil];


        // Start the savepanel
        NSSavePanel *savepanel = [NSSavePanel savePanel];
        savepanel.title = @"Save chart";

        [savepanel setAllowedFileTypes:[NSArray arrayWithObject:@"jpg"]];
        [savepanel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result)
         {
             if (NSFileHandlingPanelOKButton == result)
             {
                 NSURL* fileURL = [savepanel URL];

                 if ([fileURL.pathExtension isEqualToString:@""])
                     fileURL = [fileURL URLByAppendingPathExtension:@"jpg"];

                 [exportedData writeToURL:fileURL atomically:YES];
             }
         }];