วิธีรับข้อมูลพิกเซลจาก UIImage (Cocoa Touch) หรือ CGImage (Core Graphics)


200

ฉันมี 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;
}

คำตอบ:


249

FYI ฉันรวมคำตอบของ 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;
}

4
อย่าลืมที่จะ unpremipiply สี การคูณด้วย 1 จะไม่ทำอะไรเลย
Peter Hosey

2
แม้ว่ามันจะถูกต้อง เมื่อการนับเป็นจำนวนมาก (เช่นความยาวของแถวของภาพหรือขนาดภาพทั้งหมด!) ฉันไม่ได้ประสิทธิภาพของวิธีนี้จะดีเพราะมีวัตถุ UIColor มากเกินไปหนักมาก ในชีวิตจริงเมื่อฉันต้องการพิกเซลดังนั้น UIColor ก็โอเค (NSArray ของ UIColors มากเกินไปสำหรับฉัน) และเมื่อคุณต้องการพวงสีฉันจะไม่ใช้ UIColors เนื่องจากฉันอาจใช้ OpenGL เป็นต้น ในความคิดของฉันวิธีนี้ไม่มีการใช้ชีวิตจริง แต่ดีสำหรับวัตถุประสงค์ทางการศึกษา
nacho4d

4
วิธียุ่งยากเกินไป malloc พื้นที่ขนาดใหญ่เพียงเพื่ออ่านหนึ่งพิกเซล
ragnarius

46
ใช้ CALLOC แทน MALLOC !!!! ฉันใช้รหัสนี้เพื่อทดสอบว่าพิกเซลบางตัวโปร่งใสหรือไม่และฉันได้รับข้อมูลปลอมที่พิกเซลมีความโปร่งใสเนื่องจากหน่วยความจำไม่ได้ถูกล้างก่อน การใช้ calloc (width * height, 4) แทนที่จะเป็น malloc ทำเคล็ดลับ ส่วนที่เหลือของรหัสนั้นยอดเยี่ยมขอบคุณ!
DonnaLea

5
มันเยี่ยมมาก ขอบคุณ หมายเหตุเกี่ยวกับการใช้งาน: x และ y เป็นพิกัดในรูปภาพเพื่อเริ่มรับ RGBA จากและ 'count' คือจำนวนพิกเซลจากจุดนั้นเพื่อรับ, ไปทางซ้ายไปขวาแล้วเรียงกันทีละแถว ตัวอย่างการใช้งาน: เพื่อรับ RGBAs สำหรับภาพทั้งหมด: getRGBAsFromImage:image atX:0 andY:0 count:image.size.width*image.size.height เพื่อให้ได้ RGBA สำหรับแถวสุดท้ายของรูปภาพ: getRGBAsFromImage:image atX:0 andY:image.size.height-1 count:image.size.width
แฮร์ริส

49

วิธีหนึ่งในการทำคือการวาดภาพไปยังบริบทบิตแมปที่ได้รับการสนับสนุนโดยบัฟเฟอร์ที่กำหนดสำหรับ colorspace ที่กำหนด (ในกรณีนี้คือ 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];

ฉันทำสิ่งที่คล้ายกันในแอพของฉัน ในการแยกพิกเซลออกโดยพลการคุณเพียงแค่วาดลงในบิตแมปขนาด 1x1 ที่มีรูปแบบบิตแมปที่รู้จักซึ่งเป็นการปรับต้นกำเนิดของ CGBitmapContext อย่างเหมาะสม
Mark Bessey

5
หน่วยความจำรั่ว ปล่อย rawData: ฟรี (rawData);
Adam Waite

5
CGContextDrawImageต้องมีการโต้แย้งสามครั้งและมากกว่าสองข้อเท่านั้นที่ได้รับ ... ฉันคิดว่ามันควรจะเป็นCGContextDrawImage(context, CGRectMake(0, 0, width, height), image)
user1135469

25

ถามตอบด้านเทคนิคของ Apple QA1509แสดงวิธีการง่ายๆดังต่อไปนี้:

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

ใช้CFDataGetBytePtrเพื่อไปที่ไบต์ที่แท้จริง (และCGImageGet*วิธีการต่างๆเพื่อทำความเข้าใจวิธีตีความ)


10
นี่ไม่ใช่วิธีการที่ยอดเยี่ยมเพราะรูปแบบพิกเซลมีแนวโน้มที่จะแตกต่างกันมากต่อภาพ มีหลายสิ่งที่สามารถเปลี่ยนแปลงได้รวมถึง 1. การวางแนวของภาพ 2. รูปแบบของส่วนประกอบอัลฟาและ 3. ลำดับไบต์ของ RGB ฉันใช้เวลาส่วนตัวพยายามถอดรหัสเอกสารของ Apple เกี่ยวกับวิธีการทำเช่นนี้ แต่ฉันไม่แน่ใจว่ามันคุ้มค่า ถ้าคุณต้องการให้มันเสร็จเร็วแค่แก้ปัญหาของ keremk
ไทเลอร์

1
วิธีนี้ให้รูปแบบ BGR เสมอแม้ว่าฉันจะบันทึกภาพ (จากแอพของฉันใน
colourspace

1
@Soumyaljit นี่จะเป็นการคัดลอกข้อมูลในรูปแบบซึ่งข้อมูล CGImageRef ถูกเก็บไว้ในตอนแรก ในกรณีส่วนใหญ่สิ่งนี้จะเป็น BGRA แต่อาจเป็น YUV
Cameron Lowell Palmer

18

ไม่อยากจะเชื่อเลยว่าไม่มีคำตอบเดียวที่ถูกต้องที่นี่ ไม่จำเป็นต้องจัดสรรพอยน์เตอร์และค่าที่ยังไม่มีการแยกยังคงต้องทำให้เป็นมาตรฐาน หากต้องการตัดการไล่ล่านี่เป็นเวอร์ชั่นที่ถูกต้องสำหรับ 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)
        }
    }
}

เหตุผลที่คุณต้องวาด / แปลงภาพก่อนลงในบัฟเฟอร์เป็นเพราะภาพสามารถมีหลายรูปแบบที่แตกต่างกัน ขั้นตอนนี้จำเป็นต้องแปลงเป็นรูปแบบที่สอดคล้องกันที่คุณสามารถอ่านได้


ฉันจะใช้ส่วนขยายนี้สำหรับรูปภาพของฉันได้อย่างไร ให้ imageObj = UIImage (ชื่อ: "greencolorImg.png")
Sagar Sukode

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

โปรดทราบว่าpt1และpt2เป็นCGPointตัวแปร
AnBisw

บันทึกวันของฉัน :)
Dari

1
@ErikAigner จะใช้งานได้หรือไม่หากฉันต้องการสีของแต่ละพิกเซลของภาพ ประสิทธิภาพมีค่าใช้จ่ายเท่าไหร่
Ameet Dhas

9

นี่คือเธรด SO ที่ @Matt แสดงเฉพาะพิกเซลที่ต้องการในบริบท 1x1 โดยการแทนที่รูปภาพเพื่อให้พิกเซลที่ต้องการสอดคล้องกับพิกเซลหนึ่งพิกเซลในบริบท


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

ฉันโพสต์สิ่งนี้และมันใช้งานได้สำหรับฉัน แต่จากบัฟเฟอร์กลับไปเป็น UIImage ที่ฉันไม่สามารถคิดออกได้ความคิดอะไรบ้าง
Nidal Fakhouri

8

UIImage เป็น wrapper ที่ไบต์คือ CGImage หรือ CIImage

ตามการอ้างอิงของApple บน UIImageวัตถุนั้นไม่เปลี่ยนรูปและคุณไม่สามารถเข้าถึงไบต์สำรอง แม้ว่าจะเป็นความจริงที่ว่าคุณสามารถเข้าถึงข้อมูล CGImage หากคุณเติมข้อมูลUIImageด้วยCGImage(อย่างชัดเจนหรือโดยปริยาย) มันจะกลับมาNULLหากข้อมูลUIImageนั้นได้รับการสนับสนุนจากCIImageและในทางกลับกัน

วัตถุรูปภาพไม่ให้การเข้าถึงโดยตรงกับข้อมูลรูปภาพพื้นฐาน อย่างไรก็ตามคุณสามารถดึงข้อมูลรูปภาพในรูปแบบอื่นเพื่อใช้ในแอพของคุณ โดยเฉพาะคุณสามารถใช้คุณสมบัติ cgImage และ ciImage เพื่อดึงเวอร์ชันของอิมเมจที่เข้ากันได้กับ Core Graphics และ Core Image ตามลำดับ คุณยังสามารถใช้ฟังก์ชันUIImagePNGR แทนการนำเสนอ ( :) และ UIImageJPEGRepresentation ( : _ :) เพื่อสร้างวัตถุ NSData ที่มีข้อมูลภาพในรูปแบบ PNG หรือ JPEG

เทคนิคทั่วไปในการแก้ไขปัญหานี้

ตามที่ระบุไว้ตัวเลือกของคุณคือ

  • UIImagePNGR การนำเสนอหรือ JPEG
  • ตรวจสอบว่าภาพมีข้อมูลการสำรอง CGImage หรือ CII และไปที่นั่นหรือไม่

ทั้งสองนี้เป็นเทคนิคที่ดีโดยเฉพาะถ้าคุณต้องการเอาต์พุตที่ไม่ใช่ข้อมูล ARGB, PNG หรือ JPEG และข้อมูลยังไม่ได้รับการสนับสนุนจาก CIImage

คำแนะนำของฉันลองใช้ CIImage

ในขณะที่การพัฒนาโครงการของคุณมันอาจเหมาะสมกว่าสำหรับคุณที่จะหลีกเลี่ยง UIImage ทั้งหมดและเลือกอย่างอื่น UIImage ในฐานะผู้ห่อหุ้มรูปภาพ Obj-C นั้นมักได้รับการสนับสนุนจาก CGImage จนถึงจุดที่เรารับอนุญาต CIImage มีแนวโน้มที่จะเป็นรูปแบบ wrapper ที่ดีกว่าซึ่งคุณสามารถใช้CIContextเพื่อสร้างรูปแบบที่คุณต้องการโดยไม่จำเป็นต้องรู้ว่ามันถูกสร้างขึ้นมาอย่างไร ในกรณีของคุณการรับบิตแมปจะเป็นเรื่องของการโทร

- แสดงผล: toBitmap: rowBytes: ขอบเขต: รูปแบบ: colorSpace:

ในฐานะโบนัสที่เพิ่มเข้ามาคุณสามารถเริ่มทำการปรับแต่งภาพได้อย่างดี วิธีนี้จะช่วยแก้ปัญหามากมายที่ภาพคว่ำหรือจำเป็นต้องหมุน / ปรับขนาด ฯลฯ


6

การสร้างคำตอบของ 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
}


3

รุ่น Swift 5

คำตอบที่ให้ไว้ที่นี่อาจล้าสมัยหรือไม่ถูกต้องเพราะไม่ได้คำนึงถึงสิ่งต่อไปนี้:

  1. ขนาดพิกเซลของภาพอาจแตกต่างจากขนาดจุดที่ถูกส่งกลับโดย/image.size.widthimage.size.height
  2. อาจมีเลย์เอาต์ต่าง ๆ ที่ใช้โดยองค์ประกอบพิกเซลในภาพเช่น BGRA, ABGR, ARGB เป็นต้นหรืออาจไม่มีส่วนประกอบอัลฟาเลยเช่น BGR และ RGB ตัวอย่างเช่นUIView.drawHierarchy(in:afterScreenUpdates:)วิธีการสามารถสร้างภาพ BGRA
  3. ส่วนประกอบสีสามารถถูกกำหนดล่วงหน้าโดยอัลฟ่าสำหรับพิกเซลทั้งหมดในภาพและจำเป็นต้องหารด้วยอัลฟาเพื่อคืนค่าสีดั้งเดิม
  4. สำหรับการเพิ่มประสิทธิภาพหน่วยความจำที่ใช้โดยCGImageขนาดของแถวพิกเซลเป็นไบต์อาจมากกว่าการคูณความกว้างพิกเซลเพียง 4

รหัสด้านล่างคือการจัดหาโซลูชัน Swift 5 สากลเพื่อรับUIColorพิกเซลสำหรับกรณีพิเศษทั้งหมดดังกล่าว รหัสนี้เหมาะสำหรับการใช้งานและความชัดเจนไม่ใช่เพื่อประสิทธิภาพ

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
    }

}

แล้วการเปลี่ยนแปลงปฐมนิเทศล่ะ? คุณไม่จำเป็นต้องตรวจสอบ UIImage การเข้าร่วมด้วยหรือไม่
endavid

นอกจากนี้คุณจะหายไปในกรณีที่มีเพียงอัลฟาcomponentLayout .alphaOnly
endavid

@endavid ไม่รองรับ "Alpha only" (เนื่องจากเป็นกรณีที่หายากมาก) การวางแนวภาพไม่อยู่ในขอบเขตของรหัสนี้ แต่มีแหล่งข้อมูลมากมายเกี่ยวกับวิธีการวางแนว a ตามUIImageปกติซึ่งเป็นสิ่งที่คุณต้องทำก่อนที่จะเริ่มอ่านสีของพิกเซล
Desmond Hume

2

จากคำตอบที่แตกต่างกัน แต่ส่วนใหญ่จะเกี่ยวกับสิ่งนี้สิ่งนี้ได้ผลกับสิ่งที่ฉันต้องการ:

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

อันเป็นผลมาจากเส้นนี้คุณจะมีพิกเซลในรูปแบบ AARRGGBB กับ alpha ตั้งเสมอ FF ใน 4 pixel1ไบต์จำนวนเต็มไม่ได้ลงนาม


1

ในการเข้าถึงค่า RGB แบบดิบของ UIImage ใน Swift 5 ให้ใช้ CGImage และ dataProvider

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-raw-pixels/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.