如何水平移动图像以创建循环效果?

时间:2018-12-22 20:28:46

标签: cocoa nsimage cifilter

如何水平移动NSImage,使移动的像素出现在另一侧,使其看起来像一个循环? 目前,我正在使用drawInRect。有没有CIFilter或更聪明的方法可以做到这一点?

looped world map

- (CIImage *)image:(NSImage *)image shiftedBy:(CGFloat)shiftAmount
{

    NSUInteger width = image.size.width;
    NSUInteger height = image.size.height;
    NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                  pixelsWide:width
                                                  pixelsHigh:height
                                               bitsPerSample:8
                                             samplesPerPixel:4
                                                    hasAlpha:YES
                                                    isPlanar:NO
                                              colorSpaceName:NSDeviceRGBColorSpace
                                                 bytesPerRow:0
                                                bitsPerPixel:0];
    [rep setSize:NSMakeSize(width, height)];
    [NSGraphicsContext saveGraphicsState];
    NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:rep];
    [NSGraphicsContext setCurrentContext:context];


    CGRect rect0 = CGRectMake(0, 0, width, height);
    CGRect leftSourceRect, rightSourceRect;
    CGRectDivide(rect0, &leftSourceRect, &rightSourceRect, shiftAmount, CGRectMinXEdge);
    CGRect rightDestinationRect = CGRectOffset(leftSourceRect, width - rightSourceRect.origin.x, 0);
    CGRect leftDestinationRect = rightSourceRect;
    leftDestinationRect.origin.x = 0;

    [image drawInRect:leftDestinationRect fromRect:rightSourceRect operation:NSCompositingOperationSourceOver fraction:1.0];
    [image drawInRect:rightDestinationRect fromRect:leftSourceRect operation:NSCompositingOperationSourceOver fraction:1.0];

    [NSGraphicsContext restoreGraphicsState];
    return [[CIImage alloc] initWithBitmapImageRep:rep];
}

2 个答案:

答案 0 :(得分:0)

我用CIFilter尝试过,但是性能降低了3-4倍。但是,该代码更具可读性。

- (CIImage *)image:(NSImage *)image shiftXBy:(CGFloat)shiftX YBy:(CGFloat)shiftY
{
    //avoid calling TIFFRepresentation here cause the performance hit is even bigger
    CIImage *ciImage = [[CIImage alloc] initWithData:[image TIFFRepresentation]];
    CGAffineTransform xform = CGAffineTransformIdentity;
    NSValue *xformObj = [NSValue valueWithBytes:&xform objCType:@encode(CGAffineTransform)];
    ciImage = [ciImage imageByApplyingFilter:@"CIAffineTile"
                         withInputParameters:@{kCIInputTransformKey : xformObj} ];
    ciImage = [ciImage imageByCroppingToRect:CGRectMake(shiftX, shiftY, image.size.width, image.size.height)];
    return ciImage;
}

答案 1 :(得分:0)

为获得最佳性能,您需要使用CALayer。这是基本概念:

  • 您的NSView子类应将wantsLayerlayerUsesCoreImageFilters设置为true
  • 将图像分配到content的{​​{1}}属性(或添加新的子图层)。
  • 创建NSView.layer过滤器并将其添加到图层。

现在,您可以更改滤镜的值,而无需重新加载或重绘图像。这一切将通过硬件加速。