Как сместить изображение по горизонтали, чтобы создать эффект петли? - PullRequest
0 голосов
/ 22 декабря 2018

Как сместить NSImage по горизонтали, чтобы смещенные пиксели появлялись на другой стороне, чтобы он выглядел как петля?В настоящее время я использую drawInRect.Есть ли какой-нибудь CIF-фильтр или более разумный способ сделать это?

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 голосов
/ 25 декабря 2018

Для оптимальной производительности вам нужно использовать CALayer.Вот основная концепция:

  • Ваш подкласс NSView должен иметь wantsLayer и layerUsesCoreImageFilters, установленный на true.
  • Назначить ваше изображение для content свойство NSView.layer (или добавить новый подслой).
  • Создать CIAffineTile фильтр и добавить его в слой.

Теперь вы можете изменять значения фильтра без перезагрузки или перерисовкиобраз.Это все будет аппаратно ускорено.

0 голосов
/ 23 декабря 2018

Я пробовал это с 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;
}
...