在一开始拿到这个项目的时候, 我是觉得很轻松的,以前做工PHP的验证码生成和自动识别项目,很轻松完成。想必是当时的php库比较的完善吧,也有可能当时涉及的比较浅,压根没有机会去触及较深层的知识。这次花了好几天的时间去解决一个问题还是没解决掉,让我感触颇深。在国内论坛发帖也没有人回,最后还是在stackoverflow(问题链接)上发帖有两个大神一语道破天机,还附上了apple开发者档案的解决方法,才让度过了一个难关。特此把自己觉得有用的东西写在这里,大家一起共勉。
问题1
用Photoshop生成的一张纯红色图,设置的颜色是(238,42,43)但是到最后按Apple开发者文档提到的方法取到的颜色是(231, 17,33), 查了很多东西,应该都没有错,于是继续厚着脸皮求教大神。
大神回复
Re the color issue, I just created an image in Photoshop with 238, 42, 43 and when I processed it like shown above, in my app I saw 238, 42, 43. I suspect that there's some colorspace inconsistency or something like that. I'd first open up the JPG again, and confirm that the values weren't altered in the export process or something like that.
所以我就按大神的方法用别的软件再一次取了色看用photoshop生成的图片的RGB值。结果!结果!真的如大神所言,图像倒出来颜色就变了。有问题的是图像本身,而不是程序!
另一大神直接给了一个链接
Take a look at this answer and the linked article.
这的是获益匪浅啊😭!
问题2
为什么之前获取RGB的方法会发生错误?
之前取色错误的图片的 BitmapInfo.RawValue
是 8194 也就是
CGBitmapInfo.ByteOrder32Little.RawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue
而正确的图片的BitmapInfo.RawValue 是 5
也就是说不同的BitmapInfo导致了颜色提取的错误
Apple开发者文档中关于 BitmapInfo
内容中文翻译
字节序的相关博客
Big Endian 和 Little Endian
那么最关心的问题来了 该怎么解决呢?
Apple 开发者文档QA的OC代码
void ManipulateImagePixelData(CGImageRef inImage){
// Create the bitmap context CGContextRef cgctx = CreateARGBBitmapContext(inImage);
if (cgctx == NULL) {
// error creating context
return;
}
// Get image width, height. We'll use the entire image.
size_t w = CGImageGetWidth(inImage);
size_t h = CGImageGetHeight(inImage);
CGRect rect = {{0,0},{w,h}};
// Draw the image to the bitmap context. Once we draw, the memd dory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space. CGContextDrawImage(cgctx, rect, inImage); // Now we can get a pointer to the image data associated with the bitmap // context. void *data = CGBitmapContextGetData (cgctx); if (data != NULL) { // **** You have a pointer to the image data **** // **** Do stuff with the data here **** } // When finished, release the context CGContextRelease(cgctx); // Free image data memory for the context if (data) { free(data); }}CGContextRef CreateARGBBitmapContext (CGImageRef inImage){ CGContextRef context = NULL; CGColorSpaceRef colorSpace; void * bitmapData; int bitmapByteCount; int bitmapBytesPerRow; // Get image width, height. We'll use the entire image. size_t pixelsWide = CGImageGetWidth(inImage); size_t pixelsHigh = CGImageGetHeight(inImage); // Declare the number of bytes per row. Each pixel in the bitmap in this // example is represented by 4 bytes; 8 bits each of red, green, blue, and // alpha. bitmapBytesPerRow = (pixelsWide * 4); bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); // Use the generic RGB color space. colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); if (colorSpace == NULL) { fprintf(stderr, "Error allocating color space\n"); return NULL; } // Allocate memory for image data. This is the destination in memory // where any drawing to the bitmap context will be rendered. bitmapData = malloc( bitmapByteCount ); if (bitmapData == NULL) { fprintf (stderr, "Memory not allocated!"); CGColorSpaceRelease( colorSpace ); return NULL; } // Create the bitmap context. We want pre-multiplied ARGB, 8-bits // per component. Regardless of what the source image format is // (CMYK, Grayscale, and so on) it will be converted over to the format // specified here by CGBitmapContextCreate. context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, // bits per component bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst); if (context == NULL) { free (bitmapData); fprintf (stderr, "Context not created!"); } // Make sure and release colorspace before returning CGColorSpaceRelease( colorSpace ); return context;}