From 3c6a46830dca5c4e03652a93db89d4cf0fab18a2 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 19 Feb 2022 22:13:07 +0200 Subject: [PATCH] Make GBImageView not slow --- Cocoa/Document.m | 35 ++++++++++------------- Cocoa/GBImageView.m | 67 +++++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/Cocoa/Document.m b/Cocoa/Document.m index c1e660e..dd97ac5 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -1389,28 +1389,21 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) + (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale { - CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef) data); - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); - CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - - CGImageRef iref = CGImageCreate(width, - height, - 8, - 32, - 4 * width, - colorSpaceRef, - bitmapInfo, - provider, - NULL, - true, - renderingIntent); - CGDataProviderRelease(provider); - CGColorSpaceRelease(colorSpaceRef); - - NSImage *ret = [[NSImage alloc] initWithCGImage:iref size:NSMakeSize(width * scale, height * scale)]; - CGImageRelease(iref); + NSImage *ret = [[NSImage alloc] initWithSize:NSMakeSize(width * scale, height * scale)]; + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:3 + hasAlpha:false + isPlanar:false + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 + bytesPerRow:4 * width + bitsPerPixel:32]; + memcpy(rep.bitmapData, data.bytes, data.length); + [ret addRepresentation:rep]; return ret; } diff --git a/Cocoa/GBImageView.m b/Cocoa/GBImageView.m index 3525e72..406a0ec 100644 --- a/Cocoa/GBImageView.m +++ b/Cocoa/GBImageView.m @@ -10,18 +10,18 @@ } @end -@implementation GBImageView -{ - NSTrackingArea *trackingArea; -} +@interface GBGridView : NSView +@end + +@implementation GBGridView + - (void)drawRect:(NSRect)dirtyRect { - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - CGContextSetInterpolationQuality(context, kCGInterpolationNone); - [super drawRect:dirtyRect]; - CGFloat y_ratio = self.frame.size.height / self.image.size.height; - CGFloat x_ratio = self.frame.size.width / self.image.size.width; - for (GBImageViewGridConfiguration *conf in self.verticalGrids) { + GBImageView *parent = (GBImageView *)self.superview; + + CGFloat y_ratio = parent.frame.size.height / parent.image.size.height; + CGFloat x_ratio = parent.frame.size.width / parent.image.size.width; + for (GBImageViewGridConfiguration *conf in parent.verticalGrids) { [conf.color set]; for (CGFloat y = conf.size * y_ratio; y < self.frame.size.height; y += conf.size * y_ratio) { NSBezierPath *line = [NSBezierPath bezierPath]; @@ -32,7 +32,7 @@ } } - for (GBImageViewGridConfiguration *conf in self.horizontalGrids) { + for (GBImageViewGridConfiguration *conf in parent.horizontalGrids) { [conf.color set]; for (CGFloat x = conf.size * x_ratio; x < self.frame.size.width; x += conf.size * x_ratio) { NSBezierPath *line = [NSBezierPath bezierPath]; @@ -43,11 +43,11 @@ } } - if (self.displayScrollRect) { + if (parent.displayScrollRect) { NSBezierPath *path = [NSBezierPath bezierPathWithRect:CGRectInfinite]; for (unsigned x = 0; x < 2; x++) { for (unsigned y = 0; y < 2; y++) { - NSRect rect = self.scrollRect; + NSRect rect = parent.scrollRect; rect.origin.x *= x_ratio; rect.origin.y *= y_ratio; rect.size.width *= x_ratio; @@ -56,7 +56,7 @@ rect.origin.x -= self.frame.size.width * x; rect.origin.y += self.frame.size.height * y; - + NSBezierPath *subpath = [NSBezierPath bezierPathWithRect:rect]; [path appendBezierPath:subpath]; @@ -72,36 +72,61 @@ [path stroke]; } } +@end + +@implementation GBImageView +{ + NSTrackingArea *_trackingArea; + GBGridView *_gridView; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + self.wantsLayer = true; + _gridView = [[GBGridView alloc] initWithFrame:self.bounds]; + _gridView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [self addSubview:_gridView]; + return self; +} + +- (void)setImage:(NSImage *)image +{ + [super setImage:image]; + for (CALayer *layer in self.layer.sublayers) { + layer.magnificationFilter = kCAFilterNearest; + } +} - (void)setHorizontalGrids:(NSArray *)horizontalGrids { self->_horizontalGrids = horizontalGrids; - [self setNeedsDisplay]; + [_gridView setNeedsDisplay:true]; } - (void)setVerticalGrids:(NSArray *)verticalGrids { self->_verticalGrids = verticalGrids; - [self setNeedsDisplay]; + [_gridView setNeedsDisplay:true]; } - (void)setDisplayScrollRect:(bool)displayScrollRect { self->_displayScrollRect = displayScrollRect; - [self setNeedsDisplay]; + [_gridView setNeedsDisplay:true]; } - (void)updateTrackingAreas { - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; + if (_trackingArea != nil) { + [self removeTrackingArea:_trackingArea]; } - trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] + _trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingMouseMoved owner:self userInfo:nil]; - [self addTrackingArea:trackingArea]; + [self addTrackingArea:_trackingArea]; } - (void)mouseExited:(NSEvent *)theEvent