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;
}
답변
이를 수행하는 한 가지 방법은 이미지를 주어진 색상 공간 (이 경우 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*
해석 방법을 이해하기위한 다양한 방법) 를 얻는 데 사용하십시오 .
답변
여기에 하나의 정답 이 없다는 것을 믿을 수 없었 습니다. 포인터를 할당 할 필요가 없으며 곱하지 않은 값은 여전히 정규화해야합니다. 추격을 자르려면 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)
}
}
}
이미지를 먼저 버퍼로 그리거나 변환해야하는 이유는 이미지가 여러 가지 형식을 가질 수 있기 때문입니다. 이 단계는 읽을 수있는 일관된 형식으로 변환하는 데 필요합니다.
답변
다음은 @Matt가 원하는 픽셀이 컨텍스트의 한 픽셀과 정렬되도록 이미지를 대체하여 원하는 픽셀 만 1×1 컨텍스트로 렌더링 하는 SO 스레드 입니다.
답변
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);
답변
UIImage는 바이트가 CGImage 또는 CIImage 인 랩퍼입니다.
UIImage 의 Apple Reference에 따르면 객체는 변경할 수 없으며 백업 바이트에 액세스 할 수 없습니다. 를 (명시 적으로 또는 암시 적으로) 채운 경우 CGImage 데이터에 액세스 할 수있는 것이 사실이지만, UIImage
a 로 뒷받침 되면 그 반대로 CGImage
반환 NULL
됩니다 .UIImage
CIImage
이미지 객체는 기본 이미지 데이터에 직접 액세스 할 수 없습니다. 그러나 앱에서 사용하기 위해 다른 형식으로 이미지 데이터를 검색 할 수 있습니다. 특히 cgImage 및 ciImage 속성을 사용하여 각각 Core Graphics 및 Core Image와 호환되는 이미지 버전을 검색 할 수 있습니다. UIImagePNGRepresentation ( 🙂 및 UIImageJPEGRepresentation ( : _ 🙂 함수를 사용하여 PNG 또는 JPEG 형식의 이미지 데이터를 포함하는 NSData 객체를 생성 할 수도 있습니다 .
이 문제를 해결하는 일반적인 방법
명시된 바와 같이 귀하의 옵션은
- UIImagePNGRepresentation 또는 JPEG
- 이미지에 CGImage 또는 CIImage 백업 데이터가 있는지 확인하고이를 가져옵니다.
ARGB, PNG 또는 JPEG 데이터가 아닌 출력을 원하고 데이터가 이미 CIImage에 의해 백업되지 않은 경우에는 이들 중 어느 것도 특히 유용한 트릭이 아닙니다.
내 추천, CIImage를 사용해보십시오
프로젝트를 개발하는 동안 UIImage를 완전히 피하고 다른 것을 선택하는 것이 더 합리적 일 수 있습니다. Obj-C 이미지 래퍼 인 UIImage는 종종 CGImage에 의해 당연한 것으로 간주됩니다. CIImage는 CIContext 를 사용하여 원하는 형식을 만들지 않고도 원하는 형식을 얻을 수 있다는 점에서 더 나은 래퍼 형식입니다 . 귀하의 경우 비트 맵을 얻는 것은 전화의 문제입니다
-렌더 : toBitmap : rowBytes : bounds : format : colorSpace :
추가 보너스로 필터를 이미지에 연결하여 이미지를 멋지게 조작 할 수 있습니다. 이렇게하면 이미지가 거꾸로되어 있거나 회전 / 크기 조정되어야하는 많은 문제가 해결됩니다.