PDA

View Full Version : Saving NSView to Bitmap -- Explanation inside




slooksterPSV
Jul 13, 2006, 12:52 AM
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.



HiRez
Jul 13, 2006, 02:08 AM
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?

slooksterPSV
Jul 13, 2006, 02:31 AM
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?
Uhh... here's my classes, you decide from there... uh yeah..


//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




//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




//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




//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

robbieduncan
Jul 13, 2006, 09:00 AM
Can you:

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

slooksterPSV
Jul 13, 2006, 10:59 AM
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];
}
}