我需要检索位图图像的给定(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;
这在运行iPhone 4和5(而不是S)的iOS7上工作得很好。
我现在正试图让它在运行iPhone 6的iOS8上工作。要做到这一点,我需要做以下修改:
int pixelInfo = ((image.size.width * floorf(pointInImage.y) * image.scale * 2) + floorf(pointInImage.x) * image.scale ) * 4;
注意代码中的额外* 2
。
我想知道为什么这个改变是必要的,这样我才能正确地应用它。它是链接到iOS8还是iPhone 6的64位架构?如果这是64位架构造成的,那么这是没有意义的,因为:
int pixelInfo = ((image.size.width * floorf(pointInImage.y) * image.scale) + floorf(pointInImage.x) * image.scale ) * 8;
有人能弄清楚这是怎么回事吗?
发布于 2015-01-28 23:06:21
同样的问题把我逼上了整个星期.
我根据PNG文件中网格中的字符进行字体处理。加载时,我分析每个字符的像素,以评估准确的宽度。这段代码多年来一直运行良好,并且刚刚开始在iPhone 6(和iPad Mini)上崩溃。
这并不是由于iOS 8造成的,因为代码仍然可以在iPhone 5和iOS 8上工作。
这也不是由于编译过程的任何改变,因为我可以在模拟器和设备上重现来自同一个项目的问题。
这是多年来行之有效的代码:
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]
************
****************
********************
**********************
***********************
************************
************************
*************************
*************************
*************************
*************************
*************************
************************
************************
***********************
***********************
*********************
*********************
*******************
*******************
*****************
*****************
*****************
*****************
*****************
****************
****************
****************
****************
****************
**************
***********
**********
*************
***************
*****************
******************
*******************
********************
********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
********************
*******************
******************
***************
************
...and和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 \x\\ iPadMini)做’黑客‘类型的事情,但老实说,我已经厌倦了把这个问题干干净净地解决掉。
也可能相关:iPhone 6 Plus resolution confusion: Xcode or Apple's website? for development
https://stackoverflow.com/questions/26059049
复制相似问题