Skip to content

Commit

Permalink
animated webp support
Browse files Browse the repository at this point in the history
  • Loading branch information
gobbledegook committed Jan 18, 2024
1 parent a8b5926 commit a1776ff
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
1 change: 1 addition & 0 deletions DYImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ typedef NS_ENUM(char, DYImageViewZoomMode) {

@interface DYImageView : NSView
@property (nonatomic) NSImage *image;
@property (nonatomic) id webpImageSource; // CGImageSourceRef
@property (nonatomic) int rotation;
@property (nonatomic) BOOL scalesUp;
@property (nonatomic) BOOL showActualSize;
Expand Down
43 changes: 41 additions & 2 deletions DYImageView.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ @implementation DYImageView
{
NSImage *image;
NSTimer *gifTimer;
NSArray *_webpFrameInfo; int _webpCurrentFrame; NSUInteger _webpFrameCount;
int rotation;
BOOL scalesUp, showActualSize, isImageFlipped;
NSRect sourceRect;
Expand Down Expand Up @@ -122,12 +123,28 @@ - (void)drawRect:(NSRect)rect {
}
NSGraphicsContext *cg = NSGraphicsContext.currentContext;
NSImageInterpolation oldInterp = cg.imageInterpolation;
cg.imageInterpolation = zoom > 1 ? NSImageInterpolationNone : NSImageInterpolationHigh;
[image drawInRect:destinationRect fromRect:srcRect operation:NSCompositingOperationSourceOver fraction:1.0];
cg.imageInterpolation = zoom >= 4 ? NSImageInterpolationNone : NSImageInterpolationHigh;
NSImage *toDraw = image;
if (_webpImageSource) {
CGImageRef webpFrame = CGImageSourceCreateImageAtIndex((CGImageSourceRef)_webpImageSource, _webpCurrentFrame, NULL);
if (webpFrame) {
toDraw = [[NSImage alloc] initWithCGImage:webpFrame size:NSZeroSize];
if (!gifTimer || gifTimer.userInfo != _webpImageSource) {
float frameDuration = [_webpFrameInfo[_webpCurrentFrame][@"DelayTime"] floatValue];
if (frameDuration < .01) frameDuration = .01; // minimum of 10ms is apparently standard
gifTimer = [NSTimer scheduledTimerWithTimeInterval:frameDuration target:self selector:@selector(animateWebp:) userInfo:_webpImageSource repeats:NO];
gifTimer.tolerance = frameDuration*0.1;
}
}
CFRelease(webpFrame);
}
[toDraw drawInRect:destinationRect fromRect:srcRect operation:NSCompositingOperationSourceOver fraction:1.0];
cg.imageInterpolation = oldInterp;

[transform invert];
[transform concat];

if (image != toDraw) return; // animating webp, so no need to check if animating gif
id rep = image.representations[0];
if ([rep isKindOfClass:[NSBitmapImageRep class]]
&& [rep valueForProperty:NSImageFrameCount]) {
Expand All @@ -153,9 +170,31 @@ - (void)animateGIF:(NSTimer *)t {
[self setNeedsDisplay:YES];
}

- (void)setWebpImageSource:(id)src {
_webpImageSource = nil;
CFDictionaryRef props = CGImageSourceCopyProperties((CGImageSourceRef)src, NULL);
if (props) {
NSArray *frameInfo = ((__bridge NSDictionary *)props)[@"{WebP}"][@"FrameInfo"];
if (frameInfo && (_webpFrameCount = frameInfo.count) > 1) {
_webpImageSource = src;
_webpFrameInfo = frameInfo;
}
CFRelease(props);
}
}

- (void)animateWebp:(NSTimer *)t {
gifTimer = nil;
if (_webpImageSource != t.userInfo) return;
if (++_webpCurrentFrame == _webpFrameCount) _webpCurrentFrame = 0;
[self setNeedsDisplay:YES];
}

- (void)setImage:(NSImage *)anImage {
if (anImage != image) {
image = anImage;
_webpImageSource = nil;
_webpCurrentFrame = 0;
}
zoomF = 0;
rotation = 0;
Expand Down
10 changes: 10 additions & 0 deletions SlideshowWindow.m
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,16 @@ - (void)displayImage {

if (hideInfoFld) infoFld.hidden = YES; // this must happen before setImage, for redraw purposes
imgView.image = img;
if ([theFile.pathExtension.lowercaseString isEqualToString:@"webp"]) {
// check for animated webp
CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:theFile isDirectory:NO], NULL);
if (src) {
if (CGImageSourceGetCount(src) > 1)
imgView.webpImageSource = CFBridgingRelease(src);
else
CFRelease(src);
}
}
if (r) imgView.rotation = r;
if (imgFlipped) imgView.imageFlipped = YES;
// ** see keyDown for specifics
Expand Down

0 comments on commit a1776ff

Please sign in to comment.