2016-07-25 19 views
0

Also, Apples Dokumentation sagt, dass CIImageEquatable entspricht. Ich würde damit meinen, dass der folgende Komponententest bestanden wird. Allerdings nicht. Ich bin daran interessiert, warum.Sollte CIII gleich sein?

func test_CIImageEqualityShouldWork() { 
    let bundle = NSBundle(forClass: PrototypeTests.self) 
    guard let path = bundle.pathForResource("testImage", ofType: "png") else { return } 
    guard let image = UIImage(contentsOfFile: path) else { return } 

    let thingy1 = CIImage(image: image) 
    let thingy2 = CIImage(image: image) 
    XCTAssert(thingy1 == thingy2) 
} 

Das Bild existiert, die guard Aussagen sowohl passieren, aber die Assertion fehlschlägt, sie sind nicht gleich.

Aus Interesse habe ich versucht, die UIImage zweimal zu erstellen und diese auch zu vergleichen. Das scheitert auch.

Antwort

2

Alle NSObject Unterklassen entsprechen Equatable und die == Funktion ruft die isEqual: Methode auf die Objekte. isEqual: Die Methode von NSObject einfach den Objektzeiger vergleicht, d.h. o1 == o2 hält, wenn o1o2 und dieselbe Objekt-Instanz beziehen.

Siehe zum Beispiel Interacting with Objective-C APIs:

Swift bietet Standardimplementierungen der Operatoren == und === und nimmt das Protokoll gleichzusetzen für Objekte, die von der NSObject-Klasse abgeleitet. Die Standardimplementierung des Operators == ruft die isEqual: -Methode auf, und die Standardimplementierung des Operators === überprüft die Zeigergleichheit. Sie sollten die Gleichheit oder Identity-Operatoren für aus Objective-C importierte Typen nicht überschreiben.

Die Basisimplementierung von isEqual: wird von der NSObject-Klasse bereitgestellt und entspricht einer Identitätsprüfung durch Zeigergleichheit.

Viele NSObject Subklassen überschreiben die isEqual: Methode (zB NSString, NSArray, NSDate, ...), aber nicht CIImage:

let thingy1 = CIImage(image: image) 
let thingy2 = CIImage(image: image) 

schafft zwei verschiedene CIImage Instanzen und diese vergleichen als "nicht gleich" .

+0

Hmm, interessant. Also habe ich auch versucht, sie in ein 'UIImage' zu ​​konvertieren, dann diese in' NSData' umzuwandeln und das zu vergleichen - immer noch fehlgeschlagen, sogar mit identischen Bildern aus dem Bundle. Sollte das funktionieren? – Luke

+0

@lukech: Sie konvertieren PNG-Datei -> UIImage -> CIllmage -> UIImage -> PNG-Daten. Ich würde nicht erwarten, dass die Daten identisch sind. –

+0

würde ich. Vielleicht ist das aber naiv. Wie auch immer, das scheint die richtige Antwort auf meine Frage zu sein, so sehr verpflichtet, danke :) – Luke

0

FlexMonkey ImageCompareDemo war ein unvollständiger Port von Facebook ios-snapshot-test-case in C++ zu Swift. Es wurde der letzte Teil des Vergleichs von Pixeln pro Pixel weggelassen. Meine ist in Swift 4, hier ist die ganze Funktion:

static func compareWithImage(reference:CGImage, target:CGImage, tolerance:CGFloat) -> Bool { 
    guard reference.width == target.width && reference.height == target.height else { return false } 
    let referenceImageSize = CGSize(width:CGFloat(reference.width), height:CGFloat(reference.height)) 
    let targetImageSize = CGSize(width:CGFloat(target.width), height:CGFloat(target.height)) 
    let minBytesPerRow = min(reference.bytesPerRow, target.bytesPerRow) 
    let referenceImageSizeBytes = Int(referenceImageSize.height) * minBytesPerRow 
    let referenceImagePixels = calloc(1, referenceImageSizeBytes) 
    let targetImagePixels = calloc(1, referenceImageSizeBytes) 
    let referenceImageCtx = CGContext(data: referenceImagePixels, 
             width: Int(referenceImageSize.width), 
             height: Int(referenceImageSize.height), 
             bitsPerComponent: reference.bitsPerComponent, 
             bytesPerRow: minBytesPerRow, 
             space: reference.colorSpace!, 
             bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) 
    let targetImageCtx = CGContext(data: targetImagePixels, 
            width: Int(targetImageSize.width), 
            height: Int(targetImageSize.height), 
            bitsPerComponent: target.bitsPerComponent, 
            bytesPerRow: minBytesPerRow, 
            space: target.colorSpace!, 
            bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) 
    guard let referenceImageContext = referenceImageCtx, let targetImageContext = targetImageCtx else { 
     return false 
    } 
    referenceImageContext.draw(reference, in:CGRect(x:0, y:0, width:referenceImageSize.width, height:referenceImageSize.height)) 
    targetImageContext.draw(target, in:CGRect(x:0, y:0, width:targetImageSize.width, height:targetImageSize.height)) 
    var imageEqual = true 
    if(tolerance == 0) { 
     imageEqual = (memcmp(referenceImagePixels, targetImagePixels, referenceImageSizeBytes) == 0) 
    } else { 
     let pixelCount = Int(referenceImageSize.width * referenceImageSize.height) 

     let p1 = convertUMRPtoUInt32Array(pointer:referenceImagePixels!, length:referenceImageSizeBytes) 
     let p2 = convertUMRPtoUInt32Array(pointer:targetImagePixels!, length:referenceImageSizeBytes) 
     var percent:CGFloat = 0 
     var numDiffPixels = 0 
     for n in 0..<pixelCount { 
      if(p1[n] != p2[n]) { 
       numDiffPixels += 1 
       percent = CGFloat(numDiffPixels)/CGFloat(pixelCount) 
       if (percent > tolerance) { 
        imageEqual = false; 
        break; 
       } 
      } 
     } 
     //print(percent) 
    } 
    return imageEqual 
} 
Verwandte Themen