UIImage(Cocoa Touch)があります。それから、CGImageか、それが利用できる他の何かを手に入れることができてうれしいです。この関数を書きたい:
- (int)getRGBAFromImage:(UIImage *)image atX:(int)xx andY:(int)yy {
// [...]
// What do I want to read about to help
// me fill in this bit, here?
// [...]
int result = (red << 24) | (green << 16) | (blue << 8) | alpha;
return result;
}
ありがとう!
参考までに、Keremkの回答と元のアウトラインを組み合わせて、タイプミスを修正し、色の配列を返すように一般化して、すべてをコンパイルしました。結果は次のとおりです。
+ (NSArray*)getRGBAsFromImage:(UIImage*)image atX:(int)x andY:(int)y count:(int)count
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
// First get the image into your data buffer
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
// Now your rawData contains the image data in the RGBA8888 pixel format.
NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel;
for (int i = 0 ; i < count ; ++i)
{
CGFloat alpha = ((CGFloat) rawData[byteIndex + 3] ) / 255.0f;
CGFloat red = ((CGFloat) rawData[byteIndex] ) / alpha;
CGFloat green = ((CGFloat) rawData[byteIndex + 1] ) / alpha;
CGFloat blue = ((CGFloat) rawData[byteIndex + 2] ) / alpha;
byteIndex += bytesPerPixel;
UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
[result addObject:acolor];
}
free(rawData);
return result;
}
それを行う1つの方法は、指定された色空間(この場合はRGB)の指定されたバッファに裏打ちされたビットマップコンテキストに画像を描画することです:(これは画像データをそのバッファにコピーするので、ピクセル値を取得する必要があるたびにこの操作を行うのではなく、キャッシュしたい)
サンプルとして以下を参照してください。
// First get the image into your data buffer
CGImageRef image = [myUIImage CGImage];
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height));
CGContextRelease(context);
// Now your rawData contains the image data in the RGBA8888 pixel format.
int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
red = rawData[byteIndex];
green = rawData[byteIndex + 1];
blue = rawData[byteIndex + 2];
alpha = rawData[byteIndex + 3];
Appleの テクニカルQ&A QA1509 は、次の簡単なアプローチを示しています。
CFDataRef CopyImagePixels(CGImageRef inImage)
{
return CGDataProviderCopyData(CGImageGetDataProvider(inImage));
}
CFDataGetBytePtr
を使用して実際のバイトを取得します(そして、さまざまなCGImageGet*
メソッドを使用してそれらを解釈する方法を理解します)。
ここに1つの正解があるとは信じられませんでした。ポインターを割り当てる必要はなく、乗算されていない値を正規化する必要があります。追いかけるために、ここにSwiftの正しいバージョンがあります。4. UIImage
には.cgImage
を使用します。
extension CGImage {
func colors(at: [CGPoint]) -> [UIColor]? {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * width
let bitsPerComponent = 8
let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo),
let ptr = context.data?.assumingMemoryBound(to: UInt8.self) else {
return nil
}
context.draw(self, in: CGRect(x: 0, y: 0, width: width, height: height))
return at.map { p in
let i = bytesPerRow * Int(p.y) + bytesPerPixel * Int(p.x)
let a = CGFloat(ptr[i + 3]) / 255.0
let r = (CGFloat(ptr[i]) / a) / 255.0
let g = (CGFloat(ptr[i + 1]) / a) / 255.0
let b = (CGFloat(ptr[i + 2]) / a) / 255.0
return UIColor(red: r, green: g, blue: b, alpha: a)
}
}
}
ここにSO thread があります。@ Mattは、目的のピクセルがコンテキスト内の1つのピクセルに揃うように画像を移動することで、目的のピクセルのみを1x1コンテキストにレンダリングします。
NSString * path = [[NSBundle mainBundle] pathForResource:@"filename" ofType:@"jpg"];
UIImage * img = [[UIImage alloc]initWithContentsOfFile:path];
CGImageRef image = [img CGImage];
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image));
const unsigned char * buffer = CFDataGetBytePtr(data);
IImageのApple Reference によると、オブジェクトは不変であり、バッキングバイトにアクセスできません。 UIImage
に(明示的または暗黙的に)CGImage
を入力した場合、CGImageデータにアクセスできるのは事実ですが、NULL
がバックアップされている場合はUIImage
を返しますCIImage
によって、またはその逆。
画像オブジェクトは、基礎となる画像データへの直接アクセスを提供しません。ただし、アプリで使用するために他の形式で画像データを取得できます。具体的には、cgImageプロパティとciImageプロパティを使用して、それぞれCore GraphicsおよびCore Imageと互換性のあるイメージのバージョンを取得できます。 UIImagePNGRepresentation(:)およびUIImageJPEGRepresentation(:_ :)関数を使用して、PNGまたはJPEGの画像データを含むNSDataオブジェクトを生成することもできます。フォーマット。
述べたように、あなたのオプションは
ARGB、PNG、またはJPEGデータではなく、データがCIImageによってまだバックアップされていない出力が必要な場合、これらのどちらも特に良いトリックではありません。
プロジェクトの開発中に、UIImageを完全に避けて別のものを選択する方が理にかなっている場合があります。 UIImageは、Obj-Cイメージラッパーとして、多くの場合CGImageによって裏付けられており、当然のことと考えています。 CIImageは、 CIContext を使用して、どのように作成されたかを知らなくても、希望する形式を取得できるという点で、より優れたラッパー形式になる傾向があります。あなたの場合、ビットマップを取得するには
-render:toBitmap:rowBytes:bounds:format:colorSpace:
追加のボーナスとして、画像にフィルターをチェーンすることで、画像のニース操作を開始できます。これにより、画像が上下逆になったり、回転/スケーリングが必要になるなどの多くの問題が解決します。
OlieとAlgalの回答に基づいて、ここにSwift 3の更新された回答があります
public func getRGBAs(fromImage image: UIImage, x: Int, y: Int, count: Int) -> [UIColor] {
var result = [UIColor]()
// First get the image into your data buffer
guard let cgImage = image.cgImage else {
print("CGContext creation failed")
return []
}
let width = cgImage.width
let height = cgImage.height
let colorSpace = CGColorSpaceCreateDeviceRGB()
let rawdata = calloc(height*width*4, MemoryLayout<CUnsignedChar>.size)
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * width
let bitsPerComponent = 8
let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
guard let context = CGContext(data: rawdata, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
print("CGContext creation failed")
return result
}
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
// Now your rawData contains the image data in the RGBA8888 pixel format.
var byteIndex = bytesPerRow * y + bytesPerPixel * x
for _ in 0..<count {
let alpha = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 3, as: UInt8.self)) / 255.0
let red = CGFloat(rawdata!.load(fromByteOffset: byteIndex, as: UInt8.self)) / alpha
let green = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 1, as: UInt8.self)) / alpha
let blue = CGFloat(rawdata!.load(fromByteOffset: byteIndex + 2, as: UInt8.self)) / alpha
byteIndex += bytesPerPixel
let aColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
result.append(aColor)
}
free(rawdata)
return result
}
さまざまな答えに基づいていますが、主に this に基づいており、これは私が必要とするものに対して機能します:
UIImage *image1 = ...; // The image from where you want a pixel data
int pixelX = ...; // The X coordinate of the pixel you want to retrieve
int pixelY = ...; // The Y coordinate of the pixel you want to retrieve
uint32_t pixel1; // Where the pixel data is to be stored
CGContextRef context1 = CGBitmapContextCreate(&pixel1, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst);
CGContextDrawImage(context1, CGRectMake(-pixelX, -pixelY, CGImageGetWidth(image1.CGImage), CGImageGetHeight(image1.CGImage)), image1.CGImage);
CGContextRelease(context1);
この行の結果として、4バイトの符号なし整数pixel1
で常にFFに設定されたAARRGGBB形式のピクセルができます。