Para sua informação, combinei a resposta de Keremk com meu esboço original, limpei os erros de digitação, generalizei-a para retornar uma variedade de cores e fiz com que tudo fosse compilado. Aqui está o resultado:
+ (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;
}
getRGBAsFromImage:image atX:0 andY:0 count:image.size.width*image.size.height
Para obter RGBAs para a última linha de uma imagem:getRGBAsFromImage:image atX:0 andY:image.size.height-1 count:image.size.width
Uma maneira de fazer isso é desenhar a imagem em um contexto de bitmap que é apoiado por um determinado buffer para um determinado espaço de cores (nesse caso, é RGB): (observe que isso copiará os dados da imagem para esse buffer, então você deve deseja armazená-lo em cache em vez de fazer essa operação sempre que precisar obter valores de pixel)
Veja abaixo como uma amostra:
fonte
CGContextDrawImage
requer três argumentos e acima apenas dois são dadas ... Eu acho que deveria serCGContextDrawImage(context, CGRectMake(0, 0, width, height), image)
Perguntas e respostas técnicas da Apple O QA1509 mostra a seguinte abordagem simples:
Use
CFDataGetBytePtr
para acessar os bytes reais (e váriosCGImageGet*
métodos para entender como interpretá-los).fonte
Não conseguia acreditar que não há uma única resposta correta aqui. Não há necessidade de alocar ponteiros, e os valores não multiplicados ainda precisam ser normalizados. Para ir direto ao ponto, aqui está a versão correta do Swift 4. Para
UIImage
apenas usar.cgImage
.O motivo pelo qual você precisa desenhar / converter a imagem primeiro em um buffer é porque as imagens podem ter vários formatos diferentes. Esta etapa é necessária para convertê-lo em um formato consistente que você possa ler.
fonte
let imageObj = UIImage(named:"greencolorImg.png"); imageObj.cgImage?.colors(at: [pt1, pt2])
pt1
ept2
sãoCGPoint
variáveis.Aqui está um tópico SO em que o @Matt renderiza apenas o pixel desejado em um contexto 1x1 deslocando a imagem para que o pixel desejado se alinhe com o pixel no contexto.
fonte
fonte
UIImage é um invólucro, os bytes são CGImage ou CIImage
De acordo com a Referência da Apple na UIImage, o objeto é imutável e você não tem acesso aos bytes de backup. Embora seja verdade que você possa acessar os dados da CGImage se os tiver preenchido
UIImage
com umCGImage
(explícita ou implicitamente), ele retornaráNULL
seUIImage
for apoiado por aeCIImage
vice-versa.Truques comuns para contornar esse problema
Conforme indicado, suas opções são
Nenhum desses truques é particularmente bom se você deseja uma saída que não seja dados ARGB, PNG ou JPEG e os dados ainda não sejam suportados pelo CIImage.
Minha recomendação, tente CIImage
Ao desenvolver seu projeto, pode fazer mais sentido evitar completamente o UIImage e escolher outra coisa. UIImage, como um invólucro de imagem Obj-C, geralmente é suportado por CGImage até o ponto em que tomamos como garantido. O CIImage tende a ser um formato de wrapper melhor, pois você pode usar um CIContext para obter o formato desejado sem precisar saber como ele foi criado. No seu caso, obter o bitmap seria uma questão de chamar
- render: toBitmap: rowBytes: limites: formato: colorSpace:
Como um bônus adicional, você pode começar a fazer boas manipulações na imagem, encadeando filtros na imagem. Isso resolve muitos problemas em que a imagem está de cabeça para baixo ou precisa ser girada / redimensionada etc.
fonte
Com base na resposta de Olie e Algal, aqui está uma resposta atualizada para o Swift 3
rápido
fonte
Versão Swift 5
As respostas fornecidas aqui estão desatualizadas ou incorretas porque não levam em consideração o seguinte:
image.size.width
/image.size.height
.UIView.drawHierarchy(in:afterScreenUpdates:)
método pode produzir imagens BGRA.CGImage
, o tamanho de uma linha de pixels em bytes pode ser maior que a mera multiplicação da largura de pixels por 4.O código abaixo é fornecer uma solução universal Swift 5 para obter o
UIColor
pixel de todos os casos especiais. O código é otimizado para usabilidade e clareza, não para desempenho.fonte
componentLayout
está perdendo o caso quando há apenas alfa.alphaOnly
,.UIImage
, que é o que você faria antes de começar a ler suas cores de pixel.Com base em respostas diferentes, mas principalmente nisso , funciona para o que eu preciso:
Como resultado dessas linhas, você terá um pixel no formato AARRGGBB com alfa sempre definido como FF no número inteiro não assinado de 4 bytes
pixel1
.fonte
Para acessar os valores RGB brutos de uma UIImage no Swift 5, use a CGImage subjacente e seu dataProvider:
https://www.ralfebert.de/ios/examples/image-processing/uiimage-raw-pixels/
fonte