Saving NSView to Bitmap -- Explanation inside

Discussion in 'Mac Programming' started by slooksterPSV, Jul 12, 2006.

  1. macrumors 68030

    slooksterPSV

    Joined:
    Apr 17, 2004
    Location:
    Nowheresville
    #1
    I have an NSView subclass called StretchView. Here's what I want to do:
    Since the StretchView has scrollbars and is extended via those scrollbars I want to be able to grab the entire StretchView (including the area not visible on screen) and save that to a file.

    Now here's what I've been able to do:
    I've been able to grab the frame of the StretchView and save it as a JPEG. But i want the entire view (even the parts that are not visible). E.g.:

    I have a box like this: and the visible data is represented by V and the invisible data is represented by D:

    DDDDDDDDDDDDDDDD
    DD_______________DD
    DD|VVVVVVVVVVVV|DD
    DD|VVVVVVVVVVVV|DD
    DD|VVVVVVVVVVVV|DD
    DD|VVVVVVVVVVVV|DD
    DD|VVVVVVVVVVVV|DD
    DD|VVVVVVVVVVVV|DD
    DD--------------------DD
    DDDDDDDDDDDDDDDD

    I want to grab the visible data (V) along with the hidden data (D) and save it as a JPEG.
     

    Attached Files:

  2. macrumors 601

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #2
    How are you currently getting the data? You didn't say. Are you using NSView's dataWithPDFInsideRect: method (using the view's full bounds as the rect), and passing that to NSImage?
     
  3. thread starter macrumors 68030

    slooksterPSV

    Joined:
    Apr 17, 2004
    Location:
    Nowheresville
    #3
    Uhh... here's my classes, you decide from there... uh yeah..

    Code:
    //AppController.h
    /* AppController */
    
    #import <Cocoa/Cocoa.h>
    @class StretchView;
    
    @interface AppController : NSObject
    {
        IBOutlet NSSlider *slider;
        IBOutlet StretchView *stretchView;
    }
    - (IBAction)fade:(id)sender;
    - (IBAction)open:(id)sender;
    - (IBAction)save:(id)sender;
    @end
    
    
    Code:
    //AppController.m
    #import "AppController.h"
    #import "StretchView.h"
    
    @implementation AppController
    
    - (void)awakeFromNib
    {
    	//Make sure the slider and the stretch view
    	//agree on the initial opacity
    	[slider setFloatValue:0.5];
    	[stretchView setOpacity:0.5];
    }
    
    - (IBAction)fade:(id)sender
    {
    	//The sender is the slider
    	[stretchView setOpacity:[sender floatValue]];
    }
    
    - (void)openPanelDidEnd:(NSOpenPanel *)openPanel returnCode:(int)returnCode contextInfo:(void *)x
    {
    	NSString *path;
    	NSImage *image;
    	
    	//Did they choose open?
    	if(returnCode == NSOKButton) {
    		path = [openPanel filename];
    		image = [[NSImage alloc] initWithContentsOfFile:path];
    		//image = [NSKeyedUnarchiver unarchiveObjectWithFile: path];
    		[stretchView setImage:image];
    		[image release];
    	}
    }
    
    - (void)savePanelDidEnd:(NSOpenPanel *)savePanel returnCode:(int)returnCode contextInfo:(void *)x
    {
    	NSString *path, *fullpath;
    	//NSData *tiff_data = [[NSdata alloc] initWithData: [ 
    	
    	if(returnCode == NSOKButton) {
    		fullpath = [savePanel filename];
    		path = fullpath;
    		NSLog(@"Path Extension: %@", [fullpath pathExtension]);
    		if([[path pathExtension] length] ==  0)
    		{
    			NSLog(@"This is fake");
    			path = [fullpath stringByAppendingPathExtension: @"jpeg"];
    		}
    		[stretchView display];
    		
    		[stretchView lockFocus];
    
    		NSBitmapImageRep *bits;
    		bits = [[NSBitmapImageRep alloc]
               initWithFocusedViewRect:[stretchView frame]];
    		   
    		[stretchView unlockFocus];
    		
    		//NSData *imageData = [image  TIFFRepresentation];
    		NSData *imageData;// = [stretchView TIFFRepresentation];
    		//NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
    		//NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
    		NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
    		//imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
    		imageData = [bits representationUsingType:NSJPEGFileType properties:imageProps];
    		[imageData writeToFile:path atomically:NO];
    
    	}
    }
    
    - (IBAction)open:(id)sender
    {
    	NSOpenPanel *panel = [NSOpenPanel openPanel];
    	
    	//Run the open panel
    	[panel beginSheetForDirectory:nil 
    		file:nil 
    		types:[NSImage imageFileTypes] 
    		modalForWindow:[stretchView window] 
    		modalDelegate:self 
    		didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
    		contextInfo:NULL];
    }
    
    -(IBAction)save:(id)sender
    {
    	NSSavePanel *panel = [NSSavePanel savePanel];
    	[panel beginSheetForDirectory:nil
    		file:@"untitled.jpeg" 
    		modalForWindow:[stretchView window]
    		modalDelegate:self 
    		didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) 
    		contextInfo:NULL];
    
    }
    
    @end
    
    
    Code:
    //StretchView.h
    /* StretchView */
    
    #import <Cocoa/Cocoa.h>
    
    @interface StretchView : NSView
    {
    	NSPoint downPoint;
    	NSPoint currentPoint;
    	NSBezierPath *path;
    	NSData *viewData;
    	NSImage *image;
    	float opacity;
    }
    
    - (void)setImage:(NSImage *)newImage;
    - (NSImage*)image;
    - (void)setOpacity:(float)x;
    - (NSPoint)randomPoint;
    - (NSRect)currentRect;
    - (void)setViewData;
    - (NSData *)data;
    @end
    
    
    Code:
    //StretchView.m
    #import "StretchView.h"
    
    @implementation StretchView
    
    - (id)initWithFrame:(NSRect)frameRect
    {
    	int i;
    	NSPoint p;
    	
    	if (self = [super initWithFrame:frameRect]) {
    		//Seed the random number generator
    		srandom(time(NULL));
    		
    		//Create a path object
    		path = [[NSBezierPath alloc] init];
    		[path setLineWidth:3.0];
    		p = [self randomPoint];
    		[path moveToPoint: p];
    		for (i = 0; i < 15; i++) {
    			p = [self randomPoint];
    			[path lineToPoint: p];
    		}
    		[path closePath];
    	}
    	return self;
    }
    
    - (void)setImage:(NSImage *)newImage
    {
    	[newImage retain];
    	[image release];
    	image = newImage;
    	
    	NSSize imageSize;
    	imageSize = [newImage size];
    	downPoint = NSZeroPoint;
    	currentPoint.x = downPoint.x + imageSize.width;
    	currentPoint.y = downPoint.y + imageSize.height;
    	
    	[self setNeedsDisplay:YES];
    }
    
    - (NSImage *)image
    {
    	return image;
    }
    
    - (void)setOpacity:(float)x
    {
    	opacity = x;
    	[self setNeedsDisplay:YES];
    }
    
    //randomPoint returns a random point inside the view
    - (NSPoint)randomPoint
    {
    	NSPoint result;
    	NSRect r;
    	int width, height;
    	r = [self bounds];
    	width = round(r.size.width);
    	height = round(r.size.height);
    	result.x = (random() % width) + r.origin.x;
    	result.y = (random() % height) + r.origin.x;
    	return result;
    }
    
    - (void)mouseDown:(NSEvent *)event
    {
    	NSPoint p = [event locationInWindow];
    	downPoint = [self convertPoint:p fromView:nil];
    	currentPoint = downPoint;
    	[self setNeedsDisplay:YES];
    }
    
    - (void)mouseDragged:(NSEvent *)event
    {
    	NSPoint p = [event locationInWindow];
    	currentPoint = [self convertPoint:p fromView:nil];
    	[[self superview] autoscroll:event];
    	[self setNeedsDisplay:YES];
    	NSLog(@"mouseDragged:");
    }
    
    - (void)mouseUp:(NSEvent *)event
    {
    	NSPoint p = [event locationInWindow];
    	currentPoint = [self convertPoint:p fromView:nil];
    	[self setNeedsDisplay:YES];
    	NSLog(@"mouseUp:");
    }
    
    - (void)drawRect:(NSRect)rect
    {
    	NSRect bounds = [self bounds];
    	
    	//Fill the view with green
    	[[NSColor greenColor] set];
    	[NSBezierPath fillRect:bounds];
    	
    	//Draw the path in white
    	[[NSColor whiteColor] set];
    	[path stroke];
    	
    	if(image) {
    		NSRect imageRect;
    		NSRect drawingRect;
    		imageRect.origin = NSZeroPoint;
    		imageRect.size = [image size];
    		drawingRect = [self currentRect];
    		[image drawInRect:drawingRect
    			fromRect:imageRect
    			operation:NSCompositeSourceOver
    			fraction:opacity];
    	}
    	[self setViewData];
    }
    
    - (NSRect)currentRect
    {
    	float minX = MIN(downPoint.x, currentPoint.x);
    	float maxX = MAX(downPoint.x, currentPoint.x);
    	float minY = MIN(downPoint.y, currentPoint.y);
    	float maxY = MAX(downPoint.y, currentPoint.y);
    	
    	return NSMakeRect(minX, minY, maxX-minX, maxY-minY);
    }
    
    - (void)setViewData
    {
    	 // Get the data into a bitmap.
    	[self lockFocus];
    	NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[self bounds]];
    	[self unlockFocus];
    
    	// Make an NSImage from our bitmap.
       NSImage *imageX = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
       [imageX addRepresentation:rep];
    
    	// Convert to TIFF, we'd like to support other file types as well.
    	viewData = [imageX TIFFRepresentation];
    }
    
    - (NSData *)data
    {
    	return viewData;
    }
    
    - (void)dealloc
    {
    	[image release];
    	[path release];
    	[super dealloc];
    }
    
    @end
    
    
     
  4. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    Can you:

    Ask the view how bit it is.
    Create an NSImage that size.
    Lock focus on the image.
    Call [view drawInRect:];
    Unlock focus?
     
  5. thread starter macrumors 68030

    slooksterPSV

    Joined:
    Apr 17, 2004
    Location:
    Nowheresville
    #5
    Here's what I had to do, and I feel like an idiot, in the next chapter, it tells you how to save a view via a PDF file. That was all I needed to do, was save it as a PDF here's the new code:

    - (void)savePanelDidEnd:(NSSavePanel *)savePanel returnCode:(int)returnCode contextInfo:(void *)x
    {
    NSRect r;
    NSData *data;

    if (returnCode == NSOKButton) {
    r = [stretchView rect];
    data = [stretchView dataWithPDFInsideRect:r];
    [data writeToFile:[savePanel filename] atomically:YES];
    }
    }
     

Share This Page