渐变纹理在视网膜 Mac 上的比例错误 [英] Gradient texture has wrong scale on retina Mac

查看:13
本文介绍了渐变纹理在视网膜 Mac 上的比例错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I wrote a gradient generating function as a category on SKTexture. It works well on 1x screens but retina renders the texture too big, double width and double height ie wrong scale. I have been trying to get it right by changing between pixels and points, but can't get it right. Can someone help me please?

+(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
}

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

So, to some sum it up, I expect to call +(SKTexture*)gradientWithSize:(const CGSize)SIZE colors:(NSArray*)colors using points for SIZE.

推荐答案

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

Updated the code as below based on LearnCocos2D's suggestion. When to scale and not to is confusing (because in the docs, CGBitmapContextCreate explicitly takes width and height in PIXELS) but this seems to have the size right also on retina screens. Still I don't know if the rendered resolution is really retina - but this is very hard to confirm using eye because after all this is a gradient... Still I'm using the same context creating functions for a texture repeater (to enable to use colorWithPatternImage with Sprite Kit). Maybe I have the time later to try a detailed texture repeated using this new version... Also leaving gradient.contentsScale = SCALE; on or off doesn't make a visible difference.

+(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 创建的黄色矩形.右边是使用上述函数生成的纹理创建的矩形.两个矩形位置相同,点大小相同,只是锚点不同.

Results below. The left is just a yellow rectangle created using SKSpriteNode. The right is a rectangle created by using the texture generated from the above function. The two rectangles are at the same position and have same point sizes, just different anchorPoints.

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 倍分辨率(视网膜)

这篇关于渐变纹理在视网膜 Mac 上的比例错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆