【问题标题】:Gradient texture has wrong scale on retina Mac渐变纹理在视网膜 Mac 上的比例错误
【发布时间】:2013-10-23 10:02:50
【问题描述】:

我在 SKTexture 上写了一个梯度生成函数作为类别。它在 1x 屏幕上运行良好,但视网膜渲染纹理太大,双倍宽度和双倍高度,即错误的比例。我一直试图通过在像素和点之间进行更改来使其正确,但无法正确。有人可以帮帮我吗?

+(SKTexture*)gradientWithSize:(const CGSize)SIZE colors:(NSArray*)colors {
    // Hopefully this function would be platform independent one day.

    // Correct way to find scale?
    DLog(@"backingScaleFactor: %f", [[NSScreen mainScreen] backingScaleFactor]);
    const CGFloat SCALE = [[NSScreen mainScreen] backingScaleFactor];
    //const size_t WIDTH_PIXELS = SIZE.width * SCALE;
    //const size_t HEIGHT_PIXELS = SIZE.height * SCALE;
    CGContextRef cgcontextref = MyCreateBitmapContext(SIZE.width, SIZE.height, SCALE);
    NSAssert(cgcontextref != NULL, @"Failed creating context!");
    //  CGBitmapContextCreate(
    //                                                    NULL, // let the OS handle the memory
    //                                                    WIDTH_PIXELS,
    //                                                    HEIGHT_PIXELS,

    CAGradientLayer* gradient = CAGradientLayer.layer;
    //gradient.contentsScale = SCALE;
    gradient.frame = CGRectMake(0, 0, SIZE.width, SIZE.height);

    NSMutableArray* convertedcolors = [NSMutableArray array];
    for (SKColor* skcolor in colors) {
        [convertedcolors addObject:(id)skcolor.CGColor];
    }
    gradient.colors = convertedcolors;
    [gradient renderInContext:cgcontextref];

    CGImageRef imageref = CGBitmapContextCreateImage(cgcontextref);
    DLog(@"imageref pixel size: %zu %zu", CGImageGetWidth(imageref), CGImageGetHeight(imageref));

    SKTexture* texture1 = [SKTexture textureWithCGImage:imageref];
    DLog(@"size of gradient texture: %@", NSStringFromSize(texture1.size));

    CGImageRelease(imageref);

    CGContextRelease(cgcontextref);

    return texture1;
}
CGContextRef MyCreateBitmapContext(const size_t POINTS_W, const size_t POINTS_H, const CGFloat SCALE) {
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    //int             bitmapByteCount;
    size_t             bitmapBytesPerRow;

    const size_t PIXELS_W = POINTS_W * SCALE;
    const size_t PIXELS_H = POINTS_H * SCALE;

    bitmapBytesPerRow   = (PIXELS_W * 4);// 1
    //bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 2
    bitmapData = NULL;

#define kBitmapInfo     kCGImageAlphaPremultipliedLast
    //#define kBitmapInfo       kCGImageAlphaPremultipliedFirst
    //#define kBitmapInfo       kCGImageAlphaNoneSkipFirst
    // According to http://stackoverflow.com/a/18921840/129202 it should be safe to just cast
    CGBitmapInfo bitmapinfo = (CGBitmapInfo)kBitmapInfo; //kCGImageAlphaNoneSkipFirst; //0; //kCGBitmapAlphaInfoMask; //kCGImageAlphaNone; //kCGImageAlphaNoneSkipFirst;
    context = CGBitmapContextCreate (bitmapData,// 4
                                     PIXELS_W,
                                     PIXELS_H,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     bitmapinfo
                                     );
    if (context == NULL) {
        free (bitmapData);// 5
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace );// 6

    // TEST!!
//  CGContextClipToRect(context, CGRectMake(0, 0, POINTS_W, POINTS_H));
    CGContextClipToRect(context, CGRectMake(0, 0, PIXELS_W, PIXELS_H));
    CGContextScaleCTM(context, SCALE, SCALE);

    return context;// 7
}

所以,总而言之,我希望使用点数来调用+(SKTexture*)gradientWithSize:(const CGSize)SIZE colors:(NSArray*)colors

【问题讨论】:

  • 你试过不缩放吗?正如这个问题的已接受答案stackoverflow.com/questions/10867767/… 所暗示的,也许位图会在视网膜设备上自动变成视网膜大小
  • 看看这个约翰尼,将点等乘以正确的比例,看来你可以从中创建 UIImage,并给它一个正确的比例,但我不知道你是否可以这样做操作系统?不管怎样,看看这个:stackoverflow.com/questions/4707465/…
  • LearnCocos2D:谢谢,我根据您的建议添加了答案。但是不确定它是否 100% 正确。 AwDogsGo2Heaven:抱歉,不能使用 UIImage,因为我在 Mac 上使用了它。我们可以在这些平台上获得的最接近共享图像格式的东西是 CGImageRef 我猜。

标签: macos scale sprite-kit retina


【解决方案1】:

根据 LearnCocos2D 的建议更新了如下代码。何时缩放而不是令人困惑(因为在文档中,CGBitmapContextCreate 明确采用 PIXELS 中的宽度和高度)但这似乎在视网膜屏幕上也具有正确的大小。我仍然不知道渲染的分辨率是否真的是视网膜 - 但这很难用眼睛来确认,因为毕竟这是一个渐变......我仍然使用相同的上下文创建函数来创建纹理转发器(启用使用colorWithPatternImage with Sprite Kit)。也许我以后有时间尝试使用这个新版本重复的详细纹理...... 将gradient.contentsScale = SCALE; 保持打开或关闭也不会产生明显的差异。

+(SKTexture*)gradientWithSize:(const CGSize)SIZE colors:(NSArray*)colors {
    // Hopefully this function would be platform independent one day.

    CGContextRef cgcontextref = MyCreateBitmapContext(SIZE.width, SIZE.height);
    NSAssert(cgcontextref != NULL, @"Failed creating context!");

    CAGradientLayer* gradient = CAGradientLayer.layer;
    DLog(@"gradient.contentScale: %f", gradient.contentsScale);
    //gradient.contentsScale = SCALE;
    DLog(@"gradient.contentScale: %f", gradient.contentsScale);
    gradient.frame = CGRectMake(0, 0, SIZE.width, SIZE.height);

    NSMutableArray* convertedcolors = [NSMutableArray array];
    for (SKColor* skcolor in colors) {
        [convertedcolors addObject:(id)skcolor.CGColor];
    }
    gradient.colors = convertedcolors;
    [gradient renderInContext:cgcontextref];

    CGImageRef imageref = CGBitmapContextCreateImage(cgcontextref);
    DLog(@"imageref pixel size: %zu %zu", CGImageGetWidth(imageref), CGImageGetHeight(imageref));

    SKTexture* texture1 = [SKTexture textureWithCGImage:imageref];
    DLog(@"size of gradient texture: %@", NSStringFromSize(texture1.size));

    CGImageRelease(imageref);

    CGContextRelease(cgcontextref);

    return texture1;
}
CGContextRef MyCreateBitmapContext(const size_t POINTS_W, const size_t POINTS_H/*, const CGFloat SCALE*/) {
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    size_t             bitmapBytesPerRow;

    bitmapBytesPerRow   = (POINTS_W * 4);

    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    bitmapData = NULL;

#define kBitmapInfo     kCGImageAlphaPremultipliedLast
    // According to https://stackoverflow.com/a/18921840/129202 it should be safe to just cast
    CGBitmapInfo bitmapinfo = (CGBitmapInfo)kBitmapInfo;
    context = CGBitmapContextCreate (bitmapData,
                                     POINTS_W,
                                     POINTS_H,
                                     8,
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     bitmapinfo
                                     );
    if (context == NULL) {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease(colorSpace);

    return context;
}

结果如下。左边只是一个使用 SKSpriteNode 创建的黄色矩形。右边是使用上述函数生成的纹理创建的矩形。两个矩形位置相同,点大小相同,只是锚点不同。

SKColor* color1 = SKColor.blueColor;
SKColor* color2 = [SKColor colorWithCalibratedRed:1 green:0 blue:0 alpha:0.5];
SKTexture* textureGradient = [SKTexture gradientWithSize:SIZE colors:@[color1, color2]];
SKSpriteNode* spriteGradient = [SKSpriteNode spriteNodeWithTexture:textureGradient];

1 倍分辨率

2 倍分辨率(视网膜)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多