【问题标题】:NSImage and retina display confusionNSImage 和视网膜显示混淆
【发布时间】:2012-07-05 18:09:10
【问题描述】:

我想在 NSImage 上添加十字架,这是我的代码:

-(NSSize)convertPixelSizeToPointSize:(NSSize)px
{
    CGFloat displayScale = [[NSScreen mainScreen] backingScaleFactor];
    NSSize res;
    res.width = px.width / displayScale;
    res.height = px.height / displayScale;
    return res;
}

-(void)awakeFromNib
{
    CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];

    NSLog(@"backingScaleFactor : %f",scale);

    NSImage *img = [[[NSImage alloc]initWithContentsOfFile:@"/Users/support/Pictures/cat.JPG"] autorelease];


    NSBitmapImageRep *imgRep = [NSBitmapImageRep imageRepWithData:[img TIFFRepresentation]];
    NSSize imgPixelSize = NSMakeSize([imgRep pixelsWide],[imgRep pixelsHigh]);
    NSSize imgPointSize = [self convertPixelSizeToPointSize:imgPixelSize];
    [img setSize:imgPointSize];

    NSLog(@"imgPixelSize.width: %f , imgPixelSize.height:%f",imgPixelSize.width,imgPixelSize.height);
    NSLog(@"imgPointSize.width: %f , imgPointSize.height:%f",imgPointSize.width,imgPointSize.height);

    [img lockFocus];
    NSAffineTransform *trans = [[[NSAffineTransform alloc] init] autorelease];
    [trans scaleBy:1.0 / scale];
    [trans set];

    NSBezierPath *path = [NSBezierPath bezierPath];     
    [[NSColor redColor] setStroke];
    [path moveToPoint:NSMakePoint(0.0, 0.0)];
    [path lineToPoint:NSMakePoint(imgPixelSize.width, imgPixelSize.height)];
    [path moveToPoint:NSMakePoint(0.0, imgPixelSize.height)];
    [path lineToPoint:NSMakePoint(imgPixelSize.width, 0.0)];

    [path setLineWidth:1];
    [path stroke];
    [img unlockFocus];

    [imageView setImage:img];

    imgRep = [NSBitmapImageRep imageRepWithData:[img TIFFRepresentation]];
    NSData *imageData = [imgRep representationUsingType:NSJPEGFileType properties:nil];
    [imageData writeToFile:@"/Users/support/Pictures/11-5.JPG" atomically:NO];
}

在非视网膜显示器上,结果是:

并显示控制台:

2012-07-06 00:53:09.889 RetinaTest[8074:403] backingScaleFactor : 1.000000
2012-07-06 00:53:09.901 RetinaTest[8074:403] imgPixelSize.width: 515.000000 , imgPixelSize.height:600.000000
2012-07-06 00:53:09.902 RetinaTest[8074:403] imgPointSize.width: 515.000000 , imgPointSize.height:600.000000

但是在视网膜显示器上(我没有使用真正的视网膜显示器而是 hidpi 模式):

控制台:

2012-07-06 00:56:05.071 RetinaTest[8113:403] backingScaleFactor : 2.000000
2012-07-06 00:56:05.083 RetinaTest[8113:403] imgPixelSize.width: 515.000000 , imgPixelSize.height:600.000000
2012-07-06 00:56:05.084 RetinaTest[8113:403] imgPointSize.width: 257.500000 , imgPointSize.height:300.000000

如果我省略这些行:

NSAffineTransform *trans = [[[NSAffineTransform alloc] init] autorelease];
            [trans scaleBy:1.0 / scale];
            [trans set];

但是,如果我将 [NSAffineTransform scaleBy] 更改为 1.0,结果是正确的

NSAffineTransform *trans = [[[NSAffineTransform alloc] init] autorelease];
        [trans scaleBy:1.0];
        [trans set];

控制台:

2012-07-06 01:01:03.420 RetinaTest[8126:403] backingScaleFactor : 2.000000
2012-07-06 01:01:03.431 RetinaTest[8126:403] imgPixelSize.width: 515.000000 , imgPixelSize.height:600.000000
2012-07-06 01:01:03.432 RetinaTest[8126:403] imgPointSize.width: 257.500000 , imgPointSize.height:300.000000

谁能解释一下? hidpi 模式和视网膜显示有什么区别?

【问题讨论】:

    标签: macos cocoa osx-lion retina-display nsimage


    【解决方案1】:

    我想我已经找到了答案。如果 NSAffineTransform 设置为 NSImage 的上下文,它会将坐标系转换为像素维度,即 2 x 点维度。即使它像这样是空的:

    NSAffineTransform *trans = [[[NSAffineTransform alloc] init] autorelease];
    [trans set];
    

    我不知道这是一个错误还是它的工作方式。

    【讨论】:

      【解决方案2】:

      重置转换没有错误(参考您自己的答案)。使用 hidpi 使默认转换成为让大多数高级代码按原样正常工作的转换。重置为恒等变换会撤消此操作以将坐标系与像素 1:1 对齐。

      但应该很少需要这样做。简化您的代码以取出图像代表和转换更改可以让您得到:

      NSImage *img = [[[NSImage alloc]initWithContentsOfFile:@"/Users/support/Pictures/cat.JPG"] autorelease];
      NSSize size = img.size;
      
      NSBezierPath *path = [NSBezierPath bezierPath];     
      [[NSColor redColor] setStroke];
      [path moveToPoint:NSMakePoint(0.0, 0.0)];
      [path lineToPoint:NSMakePoint(size.width, size.height)];
      [path moveToPoint:NSMakePoint(0.0, size.height)];
      [path lineToPoint:NSMakePoint(size.width, 0.0)];
      
      [path setLineWidth:1];
      [path stroke];
      [img unlockFocus];
      
      [imageView setImage:img];
      ...
      

      这应该可以工作,除了线将改为 2 个物理像素宽(但当然与常规屏幕上的图像的宽度相似)。试试这个更简单的特殊情况来解决这个问题:

      [path setLineWidth:(img.scale > 1) ? 0.5 : 1.0];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-31
        • 1970-01-01
        相关资源
        最近更新 更多