Reputation: 59
Hello I have an NSGradient which I had hoped to drawin to the rect using the following code:
[g drawInRect:[self bounds] angle:90];
However the issue is to get the PDF data using the below produces a black color rather than the gradient.
[myView dataWithPDFInsideRect:myView.bounds];
My solution currently is to create an NSImage from the gradient drawn on a rect - and draw the image - but obviously the performance of drawing this is bad - especially when changing colours.
I am trying to use the gradient as a background which you can change the colors with objects drawn on top.
Is there a better way to draw a gradient which works with dataWithPDFInsideRect, that's efficient so the NSColorWell sliders don't lag?
I'm sure there musy be an efficient way but i'm obviously looking in the wrong direction!
Upvotes: -2
Views: 102
Reputation: 77682
Tough to say, without seeing more of your code, but, here is a quick example...
Start a new MacOS app project
Add a new NSView
class named "SimpleGradientView`:
SimpleGradientView.h
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface SimpleGradientView : NSView
@end
NS_ASSUME_NONNULL_END
SimpleGradientView.m
#import "SimpleGradientView.h"
@implementation SimpleGradientView
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSGradient *bg = [[NSGradient alloc] initWithColors:@[NSColor.redColor, NSColor.yellowColor]];
[bg drawInRect:self.bounds angle:90.0];
}
@end
ViewController.h
#import <Cocoa/Cocoa.h>
@interface ViewController : NSViewController
@end
ViewController.m
#import "ViewController.h"
#import "SimpleGradientView.h"
@interface ViewController ()
{
SimpleGradientView *gradView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.preferredContentSize = NSMakeSize(600.0, 480.0);
gradView = [SimpleGradientView new];
// Create a button
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(150, 125, 100, 50)];
[button setTitle:@"Save as PDF"];
[button setButtonType:NSButtonTypeMomentaryPushIn];
[button setBezelStyle:NSBezelStyleRounded];
[button setTarget:self];
[button setAction:@selector(saveAsPDF:)];
// Create a label
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(40, 20, 200, 45)];
[label setStringValue:@"Hello, PDF!"];
[label setBezeled:NO];
[label setDrawsBackground:NO];
[label setEditable:NO];
[label setSelectable:NO];
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFont *boldItalic = [fontManager fontWithFamily:@"Verdana"
traits:NSBoldFontMask|NSItalicFontMask
weight:0 size:48];
// create an image view with image
NSImage *img = [NSImage imageWithSystemSymbolName:@"apple.logo" accessibilityDescription:@""];
NSImageView *iv = [NSImageView new];
iv.image = img;
iv.imageScaling = NSImageScaleProportionallyUpOrDown;
iv.contentTintColor = NSColor.cyanColor;
[label setFont:boldItalic];
[label setTextColor:NSColor.blueColor];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:button];
gradView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:gradView];
label.translatesAutoresizingMaskIntoConstraints = NO;
[gradView addSubview:label];
iv.translatesAutoresizingMaskIntoConstraints = NO;
[gradView addSubview:iv];
[NSLayoutConstraint activateConstraints:@[
[button.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20.0],
[button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[gradView.topAnchor constraintEqualToAnchor:button.bottomAnchor constant:20.0],
[gradView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:40.0],
[gradView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-40.0],
[gradView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-40.0],
[label.topAnchor constraintEqualToAnchor:gradView.topAnchor constant:20.0],
[label.centerXAnchor constraintEqualToAnchor:gradView.centerXAnchor],
[iv.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:20.0],
[iv.centerXAnchor constraintEqualToAnchor:gradView.centerXAnchor],
[iv.bottomAnchor constraintEqualToAnchor:gradView.bottomAnchor constant:-20.0],
[iv.widthAnchor constraintEqualToAnchor:iv.heightAnchor],
]];
}
- (void)saveAsPDF:(id)sender {
NSData *pdfData = [gradView dataWithPDFInsideRect:[gradView bounds]];
NSSavePanel *savePanel = [NSSavePanel savePanel];
[savePanel setAllowedFileTypes:@[@"pdf"]];
[savePanel setNameFieldStringValue:@"MyView.pdf"];
[savePanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
NSURL *fileURL = [savePanel URL];
[pdfData writeToURL:fileURL atomically:YES];
NSLog(@"PDF saved to %@", fileURL);
}
}];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
@end
When run, it should look like this:
Clicking the button will save the gradient view - along with its subviews - as a PDF file. Example: https://github.com/DonMag/SavePDFMacApp/blob/main/MyView.pdf
I posted the complete project here: https://github.com/DonMag/SavePDFMacApp
Edit
Curious... this is either a Bug, or there was a change that I can't find between Ventura and Sonoma
Using dataWithPDFInsideRect
does not appear to render the gradient -- either using drawRect
or using a CAGradientLayer
.
Generating a gradient image looks to be a reliable approach.
I updated my GitHub repo with an example.
Upvotes: 2