【问题标题】:Getting pixel data on iOS 8 / iPhone 6在 iOS 8 / iPhone 6 上获取像素数据
【发布时间】:2014-09-26 11:59:17
【问题描述】:

我需要检索位图图像给定 (x, y) 坐标的像素数据。多年来,我的代码如下:

_palettePixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8 *rawData = CFDataGetBytePtr(_imagePixelData);

int pixelInfo = ((image.size.width * floorf(pointInImage.y) * image.scale) + floorf(pointInImage.x) * image.scale ) * 4;

CGFloat red   = rawData[pixelInfo + 0] / 255.0;
CGFloat green = rawData[pixelInfo + 1] / 255.0;
CGFloat blue  = rawData[pixelInfo + 2] / 255.0;
CGFloat alpha = rawData[pixelInfo + 3] / 255.0;

这在我运行 iOS7 的 iPhone 4 和 5(不是 S)上完美运行。

我现在正试图让它在运行 iOS8 的 iPhone 6 上运行。为此,我需要进行此更改:

int pixelInfo = ((image.size.width * floorf(pointInImage.y) * image.scale * 2) + floorf(pointInImage.x) * image.scale ) * 4;

注意代码中多余的* 2

我想了解为什么此更改是必要的,以便我可以正确应用它。它是与 iOS8 相关联还是与 iPhone 6 的 64 位架构相关联?如果是由于 64 位架构,那么它是没有意义的,因为:

  1. 像素数据本身仍被编码为 4 个字节。
  2. 似乎是由于额外的填充而改变了每行像素数据的宽度,但该行数据的位置是相同的。即假设 8 字节像素 not 工作:

    int pixelInfo = ((image.size.width * floorf(pointInImage.y) * image.scale) + floorf(pointInImage.x) * image.scale ) * 8;

谁能解释一下发生了什么?

【问题讨论】:

    标签: ios ios7 core-graphics ios8


    【解决方案1】:

    这个问题一直困扰着我整整一周...

    我使用 PNG 文件中网格中的字符来制作字体。加载时,我分析每个字符的像素以评估确切的宽度。这段代码多年来一直运行良好,并且刚刚开始在 iPhone 6(和 iPad Mini)上破解。

    这与 iOS 8 无关,因为该代码仍然适用于装有 iOS 8 的 iPhone 5。

    这也不是因为编译过程发生了任何变化,因为我可以在模拟器和设备上从同一个项目中重现问题。

    这是使用多年的代码:

    void PixelMap::LoadPixelData (const char * imageFile)
    {
        CFStringRef filename = CFStringCreateWithCString (NULL, imageFile, kCFStringEncodingASCII),
                    fileExtension = CFStringCreateWithCString (NULL, "png", kCFStringEncodingASCII);
    
        // Open image
        CGImageRef image = SpriteManager::CreateNamedImage (filename, fileExtension);
    
        CFRelease (filename);
        CFRelease (fileExtension);
    
        if (image == NULL)
        {
            printf ("ERROR: cannot open image \"%s\"\n", imageFile);
            return;
        }
    
        // Get image information
        CGImageAlphaInfo info = CGImageGetAlphaInfo (image);
    
        BOOL hasAlpha =
        (
            (info == kCGImageAlphaPremultipliedLast) ||
            (info == kCGImageAlphaPremultipliedFirst) ||
            (info == kCGImageAlphaLast) ||
            (info == kCGImageAlphaFirst)
        );
    
        PixelFormat pixelFormat;
    
        if (CGImageGetColorSpace (image))
        {
            if (hasAlpha)
            {
                pixelFormat = format_RGBA8888;
            }
            else
            {
                pixelFormat = format_RGB565;
            }
        }
        else  // NOTE: No colorspace means a mask image
        {
            printf ("ERROR: invalid colour space for \"%s\"\nMust be RGBA8888...\n", imageFile);
            CGImageRelease (image);
    
            return;
        }
    
        // Round dimensions up to nearest power of 2
        CGSize imageSize = CGSizeMake (CGImageGetWidth (image), CGImageGetHeight (image));
    
        NSUInteger width = SpriteManager::MakePowerOf2 (imageSize.width),
                   height = SpriteManager::MakePowerOf2 (imageSize.height);
    
    #ifdef DEBUG
        // Check we're not wasting resources with padding
        if (width != imageSize.width || height != imageSize.height)
        {
            printf ("WARNING: texture \"%s\" has padded width and/or height.\n", imageFile);
        }
    
        // Check texture size is within maximum texture size
        if (width > TEXTURE_MAX_SIZE || height > TEXTURE_MAX_SIZE)
        {
            PANIC ("Texture is too big.");
        }
    #endif
    
        // Store dimensions
        m_width = (int)width;
        m_height = (int)height;
    
        // Grab the data
        if (pixelFormat == format_RGBA8888)
        {
            // Make a pixel buffer
            Allocate (width * height * 4);
    
            if (m_data == NULL)
            {
                printf ("ERROR: out of memory for PixelMap of \"%s\"\n", imageFile);
            }
            else
            {
                // Get the pixels
                CGColorSpaceRef colourSpace = CGImageGetColorSpace (image);
    
                CGContextRef context = CGBitmapContextCreate (m_data, width, height, 8, (width * 4), colourSpace, (kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
                CGContextDrawImage (context, CGRectMake (0, 0, CGImageGetWidth (image), CGImageGetHeight (image)), image);
    
                CGColorSpaceRelease (colourSpace);
                CGContextRelease (context);
    
    #ifdef DEBUG
                printf ("Loaded pixel map from texture \"%s\"\n", imageFile);
    #endif
            }
        }
        else
        {
            printf ("ERROR: invalid pixel format for \"%s\"\nMust be RGBA8888...\n", imageFile);
        }
    
        // Clean up the image
        CGImageRelease (image);
    }
    

    这是我最近尝试过的一种更简单的替代方法,可以产生完全相同的效果:

    void PixelMap::LoadImageData (const char * imageFile)
    {
        NSString * filename = [NSString stringWithUTF8String:imageFile];
    
        UIImage * image = [UIImage imageNamed:filename];
    
        m_width = (int)image.size.width;
        m_height = (int)image.size.height;
    
        Allocate (m_width * m_height * 4);
    
        CFDataRef imageData = CGDataProviderCopyData (CGImageGetDataProvider (image.CGImage));
        const UInt32 * pixels = (const UInt32 *)CFDataGetBytePtr (imageData);
    
        memcpy (m_data, pixels, m_dataSize);
    
        CFRelease (imageData);
    }
    

    这是我传递给此函数的示例字体图像:

    调查实现此功能的这两种方式的输出:

    在 iPhone 5 上(正确)...

    Pixel Map Dump [64, 128 -> 128, 192]
    
                               ************                         
                             ****************                       
                           ********************                     
                          **********************                    
                         ***********************                    
                         ************************                   
                         ************************                   
                        *************************                   
                        *************************                   
                        *************************                   
                        *************************                   
                        *************************                   
                         ************************                   
                         ************************                   
                         ***********************                    
                         ***********************                    
                          *********************                     
                          *********************                     
                           *******************                      
                           *******************                      
                            *****************                       
                            *****************                       
                            *****************                       
                            *****************                       
                            *****************                       
                            ****************                        
                            ****************                        
                            ****************                        
                            ****************                        
                            ****************                        
                             **************                         
                              ***********                           
                                **********                          
                              *************                         
                             ***************                        
                            *****************                       
                            ******************                      
                           *******************                      
                           ********************                     
                           ********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                          *********************                     
                           ********************                     
                           *******************                      
                            ******************                      
                             ***************                        
                              ************                          
    

    ...还有一部 iPhone 6...

    Pixel Map Dump [64, 128 -> 128, 192]
    
            **************                       *********          
           *****************                    **************      
           ******************                 ****************      
           ******************                 ****************      
           ******************                *****************      
            *****************               ******************      
             ****************               ******************      
             ****************              *******************      
             ***************               ***********  ******      
             ****************              **********    ****       
             *****************             **********               
             ******************           ***********     ***       
            *******************           ***********   ******      
            ********************          ************ *******      
            ********************          ********************      
            ********************          ********************      
            ********************           *******************      
           *********************           *******************      
           *********************           *******************      
          **********************           *******************      
         ***********************            ******************      
         **********************              *****************      
         **********************              *****************      
         *********************                ***************       
          ******************                    ************        
             ************                         *******           
    
    
    
    
    
    
          ***************                      *************        
         ******************                   **************        
         *******************                 ****************       
         *******************                *****************       
         *******************                *****************       
         *******************                *****************       
          ******************                *****************       
          ******************                ****************        
           ****************                 **************          
          *****************                 ****************        
          ****************                   ****************       
          ******************                  ***************       
          *******************                  ***************      
          ********************                  **************      
          ********************             ***** *************      
          ********************            ********************      
         **********************           ********************      
         **********************           ********************      
         **********************           ********************      
        ************************          ********************      
       *************************          ********************      
       **************************          ******************       
       **************************          *****************        
       **************************           ****************        
        *************************            *************          
          **********    *******                 ********            
    

    如您所见,得到的像素数据基本上已经缩放了 1/2。有一段时间我一直在指责色彩空间,但这似乎不是罪魁祸首。

    我读过的(许多)页面之一让我认为 iPhone 6 和其他出现此问题的设备在幕后某处使用每像素 64 位而不是通常的 32 位(尽管所有尝试强制32 BPP 从我这边)。

    跳到“深奥的布局”:http://www.objc.io/issue-3/moving-pixels-onto-the-screen.html

    我真的不想做“if (iPhone6 || iPadMini) do hack else work normal”之类的事情,但老实说,我已经厌倦了试图巧妙地解决这个问题。

    也可能相关:iPhone 6 Plus resolution confusion: Xcode or Apple's website? for development

    【讨论】:

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