Làm cách nào để lấy dữ liệu pixel từ UIImage (Ca cao cảm ứng) hoặc CGImage (Đồ họa lõi)?


200

Tôi có một UIImage (Ca cao cảm ứng). Từ đó, tôi rất vui khi nhận được CGImage hoặc bất cứ thứ gì bạn muốn có sẵn. Tôi muốn viết chức năng này:

- (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;
}

Câu trả lời:


249

FYI, tôi đã kết hợp câu trả lời của Keremk với phác thảo ban đầu của mình, dọn dẹp các lỗi chính tả, khái quát nó để trả về một mảng màu và có toàn bộ điều cần biên dịch. Đây là kết quả:

+ (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;
}

4
Đừng quên màu sắc khác thường. Ngoài ra, các phép nhân đó bằng 1 không làm gì cả.
Peter Hosey

2
Ngay cả khi nó đúng. Khi số lượng là một số lớn (như chiều dài của một hàng hình ảnh hoặc toàn bộ kích thước hình ảnh!) Tôi không thực hiện phương pháp này sẽ tốt vì có quá nhiều đối tượng UIColor thực sự nặng. Trong cuộc sống thực khi tôi cần một pixel thì UIColor vẫn ổn, (Một NSArray của UIColors là quá nhiều đối với tôi). Và khi bạn cần nhiều màu sắc, tôi sẽ không sử dụng UIColors vì có lẽ tôi sẽ sử dụng OpenGL, v.v. Theo tôi phương pháp này không có cách sử dụng thực tế nhưng rất tốt cho mục đích giáo dục.
nacho4d

4
Cách quá rườm rà malloc một không gian rộng lớn chỉ để đọc một pixel.
ragnarius

46
SỬ DỤNG CALLOC INSTEAD CỦA MALLOC !!!! Tôi đã sử dụng mã này để kiểm tra xem một số pixel nhất định có trong suốt không và tôi đã lấy lại thông tin không có thật trong đó các pixel có nghĩa là trong suốt vì bộ nhớ không bị xóa trước. Sử dụng calloc (width * height, 4) thay cho malloc đã thực hiện thủ thuật này. Phần còn lại của mã là tuyệt vời, CẢM ƠN!
DonnaLea

5
Điều đó thật tuyệt. Cảm ơn. Lưu ý về cách sử dụng: x và y là tọa độ trong ảnh để bắt đầu nhận RGBAs từ và 'đếm' là số pixel từ điểm đó đến, đi từ trái sang phải, sau đó theo từng hàng. Cách sử dụng ví dụ: Để nhận RGBAs cho toàn bộ hình ảnh: getRGBAsFromImage:image atX:0 andY:0 count:image.size.width*image.size.height Để nhận RGBAs cho hàng cuối cùng của hình ảnh: getRGBAsFromImage:image atX:0 andY:image.size.height-1 count:image.size.width
Harris

49

Một cách để làm là vẽ hình ảnh vào bối cảnh bitmap được hỗ trợ bởi một bộ đệm nhất định cho một không gian màu nhất định (trong trường hợp này là RGB): (lưu ý rằng điều này sẽ sao chép dữ liệu hình ảnh vào bộ đệm đó, vì vậy bạn làm muốn lưu trữ bộ đệm đó thay vì thực hiện thao tác này mỗi khi bạn cần lấy giá trị pixel)

Xem dưới đây như một mẫu:

// 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];

Tôi đã làm một cái gì đó tương tự trong ứng dụng của tôi. Để trích xuất một pixel tùy ý, bạn chỉ cần vẽ vào một bitmap 1x1 với định dạng bitmap đã biết, điều chỉnh nguồn gốc của CGBitmapContext một cách thích hợp.
Mark Bessey

5
Bộ nhớ này bị rò rỉ. Phát hành rawData: miễn phí (rawData);
Adam Chờ đợi

5
CGContextDrawImageyêu cầu ba đối số và chỉ có hai đối số được đưa ra ... Tôi nghĩ rằng nó nên đượcCGContextDrawImage(context, CGRectMake(0, 0, width, height), image)
user1135469

25

Hỏi đáp kỹ thuật của Apple QA1509 cho thấy cách tiếp cận đơn giản sau:

CFDataRef CopyImagePixels(CGImageRef inImage)
{
    return CGDataProviderCopyData(CGImageGetDataProvider(inImage));
}

Sử dụng CFDataGetBytePtrđể có được các byte thực tế (và các CGImageGet*phương thức khác nhau để hiểu cách diễn giải chúng).


10
Đây không phải là một cách tiếp cận tuyệt vời vì định dạng pixel có xu hướng thay đổi rất nhiều trên mỗi hình ảnh. Có một số điều có thể thay đổi, bao gồm 1. hướng của hình ảnh 2. định dạng của thành phần alpha và 3. thứ tự byte của RGB. Cá nhân tôi đã dành thời gian cố gắng giải mã các tài liệu của Apple về cách thực hiện việc này, nhưng tôi không chắc nó có giá trị hay không. Nếu bạn muốn nó được thực hiện nhanh chóng, chỉ cần giải pháp của keremk.
Tyler

1
Phương pháp này luôn mang lại cho tôi định dạng BGR ngay cả khi tôi lưu hình ảnh (từ trong ứng dụng của mình trong không gian màu RGBA)
Soumyajit

1
@Soumyaljit Điều này sẽ sao chép dữ liệu theo định dạng mà dữ liệu CGImageRef ban đầu được lưu trữ. Trong hầu hết các trường hợp, đây sẽ là BGRA, nhưng cũng có thể là YUV.
Cameron Lowell Palmer

18

Không thể tin rằng không có một câu trả lời đúng duy nhất ở đây. Không cần phân bổ con trỏ, và các giá trị không được xử lý vẫn cần được chuẩn hóa. Để cắt theo đuổi, đây là phiên bản chính xác cho Swift 4. UIImageChỉ cần sử dụng .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)
        }
    }
}

Lý do bạn phải vẽ / chuyển đổi hình ảnh đầu tiên thành bộ đệm là vì hình ảnh có thể có một số định dạng khác nhau. Bước này là cần thiết để chuyển đổi nó sang một định dạng nhất quán mà bạn có thể đọc.


Làm cách nào tôi có thể sử dụng tiện ích mở rộng này cho hình ảnh của mình? hãy để imageObj = UIImage (được đặt tên: "greencolorImg.png")
Sagar Sukode

let imageObj = UIImage(named:"greencolorImg.png"); imageObj.cgImage?.colors(at: [pt1, pt2])
Erik Aigner

hãy nhớ rằng pt1pt2CGPointcác biến.
AnBisw

đã cứu ngày của tôi :)
Dari

1
@ErikAigner sẽ hoạt động nếu tôi muốn lấy màu của từng pixel của hình ảnh? chi phí hiệu suất là gì?
Ameet Dhas

9

Đây là một luồng SO trong đó @Matt chỉ hiển thị pixel mong muốn thành bối cảnh 1x1 bằng cách dịch chuyển hình ảnh để pixel mong muốn thẳng hàng với một pixel trong ngữ cảnh.


9
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);

Tôi đã đăng cái này và nó hoạt động với tôi, nhưng đi từ bộ đệm trở lại UIImage tôi dường như không thể tìm ra được, có ý tưởng nào không?
Nidal Fakhouri

8

UIImage là một trình bao bọc các byte là CGImage hoặc CIImage

Theo Tài liệu tham khảo của Apple về UIImage , đối tượng là bất biến và bạn không có quyền truy cập vào các byte sao lưu. Mặc dù đúng là bạn có thể truy cập dữ liệu CGImage nếu bạn nhập dữ liệu UIImagebằng CGImage(rõ ràng hoặc ngầm), nó sẽ trả về NULLnếu UIImageđược hỗ trợ bởi a CIImagevà ngược lại.

Các đối tượng hình ảnh không cung cấp quyền truy cập trực tiếp vào dữ liệu hình ảnh cơ bản của chúng. Tuy nhiên, bạn có thể truy xuất dữ liệu hình ảnh ở các định dạng khác để sử dụng trong ứng dụng của mình. Cụ thể, bạn có thể sử dụng các thuộc tính cgImage và ciImage để truy xuất các phiên bản của hình ảnh tương thích với Core Graphics và Core Image, tương ứng. Bạn cũng có thể sử dụng các hàm UIImagePNGRepftimeation ( :) và UIImageJPEGRepftimeation ( : _ :) để tạo một đối tượng NSData chứa dữ liệu hình ảnh ở định dạng PNG hoặc JPEG.

Thủ thuật phổ biến để giải quyết vấn đề này

Như đã nêu các lựa chọn của bạn là

  • UIImagePNG Xuất hiện hoặc JPEG
  • Xác định xem hình ảnh có dữ liệu sao lưu CGImage hoặc CIImage không và lấy nó ở đó

Đây không phải là những thủ thuật đặc biệt tốt nếu bạn muốn đầu ra không phải là dữ liệu ARGB, PNG hoặc JPEG và dữ liệu chưa được CIImage hỗ trợ.

Đề nghị của tôi, hãy thử CIImage

Trong khi phát triển dự án của bạn, điều đó có thể có ý nghĩa hơn đối với bạn để tránh UIImage hoàn toàn và chọn một cái gì đó khác. UIImage, với tư cách là trình bao bọc hình ảnh Obj-C, thường được CGImage hỗ trợ đến mức chúng tôi coi đó là điều hiển nhiên. CIImage có xu hướng là một định dạng trình bao bọc tốt hơn ở chỗ bạn có thể sử dụng CIContext để lấy ra định dạng mà bạn mong muốn mà không cần biết nó được tạo như thế nào. Trong trường hợp của bạn, nhận được bitmap sẽ là một vấn đề của cuộc gọi

- kết xuất: toBitmap: rowBytes: bound: format: colorSpace:

Là một phần thưởng bổ sung, bạn có thể bắt đầu thực hiện các thao tác tốt cho hình ảnh bằng cách xâu các bộ lọc vào hình ảnh. Điều này giải quyết rất nhiều vấn đề trong đó hình ảnh bị lộn ngược hoặc cần phải được xoay / thu nhỏ, v.v.


6

Dựa trên câu trả lời của Olie và Algal, đây là câu trả lời cập nhật cho 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
}


3

Phiên bản Swift 5

Các câu trả lời được đưa ra ở đây là lỗi thời hoặc không chính xác vì chúng không tính đến các điều sau:

  1. Kích thước pixel của hình ảnh có thể khác với kích thước điểm được trả về bởi image.size.width/ image.size.height.
  2. Có thể có nhiều bố cục khác nhau được sử dụng bởi các thành phần pixel trong hình ảnh, chẳng hạn như BGRA, ABGR, ARGB, v.v. hoặc có thể không có thành phần alpha nào, chẳng hạn như BGR và RGB. Ví dụ, UIView.drawHierarchy(in:afterScreenUpdates:)phương pháp có thể tạo ra hình ảnh BGRA.
  3. Các thành phần màu có thể được xử lý trước bởi alpha cho tất cả các pixel trong ảnh và cần được chia theo alpha để khôi phục lại màu gốc.
  4. Để tối ưu hóa bộ nhớ được sử dụng bởi CGImage, kích thước của một hàng pixel tính theo byte có thể lớn hơn bội số của chiều rộng pixel bằng 4.

Mã dưới đây là cung cấp giải pháp Swift 5 phổ quát để lấy UIColorpixel cho tất cả các trường hợp đặc biệt như vậy. Mã được tối ưu hóa cho tính khả dụng và rõ ràng, không phải cho hiệu suất.

public extension UIImage {

    var pixelWidth: Int {
        return cgImage?.width ?? 0
    }

    var pixelHeight: Int {
        return cgImage?.height ?? 0
    }

    func pixelColor(x: Int, y: Int) -> UIColor {
        assert(
            0..<pixelWidth ~= x && 0..<pixelHeight ~= y,
            "Pixel coordinates are out of bounds")

        guard
            let cgImage = cgImage,
            let data = cgImage.dataProvider?.data,
            let dataPtr = CFDataGetBytePtr(data),
            let colorSpaceModel = cgImage.colorSpace?.model,
            let componentLayout = cgImage.bitmapInfo.componentLayout
        else {
            assertionFailure("Could not get a pixel of an image")
            return .clear
        }

        assert(
            colorSpaceModel == .rgb,
            "The only supported color space model is RGB")
        assert(
            cgImage.bitsPerPixel == 32 || cgImage.bitsPerPixel == 24,
            "A pixel is expected to be either 4 or 3 bytes in size")

        let bytesPerRow = cgImage.bytesPerRow
        let bytesPerPixel = cgImage.bitsPerPixel/8
        let pixelOffset = y*bytesPerRow + x*bytesPerPixel

        if componentLayout.count == 4 {
            let components = (
                dataPtr[pixelOffset + 0],
                dataPtr[pixelOffset + 1],
                dataPtr[pixelOffset + 2],
                dataPtr[pixelOffset + 3]
            )

            var alpha: UInt8 = 0
            var red: UInt8 = 0
            var green: UInt8 = 0
            var blue: UInt8 = 0

            switch componentLayout {
            case .bgra:
                alpha = components.3
                red = components.2
                green = components.1
                blue = components.0
            case .abgr:
                alpha = components.0
                red = components.3
                green = components.2
                blue = components.1
            case .argb:
                alpha = components.0
                red = components.1
                green = components.2
                blue = components.3
            case .rgba:
                alpha = components.3
                red = components.0
                green = components.1
                blue = components.2
            default:
                return .clear
            }

            // If chroma components are premultiplied by alpha and the alpha is `0`,
            // keep the chroma components to their current values.
            if cgImage.bitmapInfo.chromaIsPremultipliedByAlpha && alpha != 0 {
                let invUnitAlpha = 255/CGFloat(alpha)
                red = UInt8((CGFloat(red)*invUnitAlpha).rounded())
                green = UInt8((CGFloat(green)*invUnitAlpha).rounded())
                blue = UInt8((CGFloat(blue)*invUnitAlpha).rounded())
            }

            return .init(red: red, green: green, blue: blue, alpha: alpha)

        } else if componentLayout.count == 3 {
            let components = (
                dataPtr[pixelOffset + 0],
                dataPtr[pixelOffset + 1],
                dataPtr[pixelOffset + 2]
            )

            var red: UInt8 = 0
            var green: UInt8 = 0
            var blue: UInt8 = 0

            switch componentLayout {
            case .bgr:
                red = components.2
                green = components.1
                blue = components.0
            case .rgb:
                red = components.0
                green = components.1
                blue = components.2
            default:
                return .clear
            }

            return .init(red: red, green: green, blue: blue, alpha: UInt8(255))

        } else {
            assertionFailure("Unsupported number of pixel components")
            return .clear
        }
    }

}

public extension UIColor {

    convenience init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
        self.init(
            red: CGFloat(red)/255,
            green: CGFloat(green)/255,
            blue: CGFloat(blue)/255,
            alpha: CGFloat(alpha)/255)
    }

}

public extension CGBitmapInfo {

    enum ComponentLayout {

        case bgra
        case abgr
        case argb
        case rgba
        case bgr
        case rgb

        var count: Int {
            switch self {
            case .bgr, .rgb: return 3
            default: return 4
            }
        }

    }

    var componentLayout: ComponentLayout? {
        guard let alphaInfo = CGImageAlphaInfo(rawValue: rawValue & Self.alphaInfoMask.rawValue) else { return nil }
        let isLittleEndian = contains(.byteOrder32Little)

        if alphaInfo == .none {
            return isLittleEndian ? .bgr : .rgb
        }
        let alphaIsFirst = alphaInfo == .premultipliedFirst || alphaInfo == .first || alphaInfo == .noneSkipFirst

        if isLittleEndian {
            return alphaIsFirst ? .bgra : .abgr
        } else {
            return alphaIsFirst ? .argb : .rgba
        }
    }

    var chromaIsPremultipliedByAlpha: Bool {
        let alphaInfo = CGImageAlphaInfo(rawValue: rawValue & Self.alphaInfoMask.rawValue)
        return alphaInfo == .premultipliedFirst || alphaInfo == .premultipliedLast
    }

}

Những thay đổi trong định hướng? Bạn không cần phải kiểm tra UIImage. Yêu cầu là tốt?
endavid

Ngoài ra, bạn componentLayoutđang thiếu trường hợp khi chỉ có alpha , .alphaOnly.
endavid

@endavid "Chỉ Alpha" không được hỗ trợ (vì là trường hợp rất hiếm). Định hướng hình ảnh nằm ngoài phạm vi của mã này, nhưng có nhiều tài nguyên về cách bình thường hóa hướng của a UIImage, đó là những gì bạn sẽ làm trước khi bắt đầu đọc màu pixel của nó.
Desmond Hume

2

Dựa trên các câu trả lời khác nhau nhưng chủ yếu dựa trên điều này , điều này hoạt động cho những gì tôi cần:

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);

Kết quả của các dòng này, bạn sẽ có một pixel ở định dạng AARRGGBB với alpha luôn được đặt thành FF trong số nguyên không dấu 4 byte pixel1.


1

Để truy cập các giá trị RGB thô của UIImage trong Swift 5, hãy sử dụng CGImage bên dưới và DataProvider của nó:

import UIKit

let image = UIImage(named: "example.png")!

guard let cgImage = image.cgImage,
    let data = cgImage.dataProvider?.data,
    let bytes = CFDataGetBytePtr(data) else {
    fatalError("Couldn't access image data")
}
assert(cgImage.colorSpace?.model == .rgb)

let bytesPerPixel = cgImage.bitsPerPixel / cgImage.bitsPerComponent
for y in 0 ..< cgImage.height {
    for x in 0 ..< cgImage.width {
        let offset = (y * cgImage.bytesPerRow) + (x * bytesPerPixel)
        let components = (r: bytes[offset], g: bytes[offset + 1], b: bytes[offset + 2])
        print("[x:\(x), y:\(y)] \(components)")
    }
    print("---")
}

https://www.ralfebert.de/ios/examples/image- Processing / uiimage-tôm-pixel /

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.