GeraldTheGerm
GeraldTheGerm

Reputation: 59

most efficient way to draw a gradient Objective-C (currently NSColorWell is lagging when moving color sliders)

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

Answers (1)

DonMag
DonMag

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:

enter image description here

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

Related Questions