]> git.cworth.org Git - apitrace/blobdiff - scripts/retracediff.py
cli: use $LIB to handle multilib automagically on glibc
[apitrace] / scripts / retracediff.py
index 4ed58373f2dab00f919843eca78ccf69b2a0f466..18a97f63c158ee5473ca9b329198bc7397985c85 100755 (executable)
@@ -43,9 +43,9 @@ import jsondiff
 
 # Null file, to use when we're not interested in subprocesses output
 if platform.system() == 'Windows':
-    NULL = open('NUL:', 'wt')
+    NULL = open('NUL:', 'wb')
 else:
-    NULL = open('/dev/null', 'wt')
+    NULL = open('/dev/null', 'wb')
 
 
 class RetraceRun:
@@ -134,9 +134,23 @@ def read_pnm(stream):
     magic = magic.rstrip()
     if magic == 'P5':
         channels = 1
+        bytesPerChannel = 1
         mode = 'L'
     elif magic == 'P6':
         channels = 3
+        bytesPerChannel = 1
+        mode = 'RGB'
+    elif magic == 'Pf':
+        channels = 1
+        bytesPerChannel = 4
+        mode = 'R'
+    elif magic == 'PF':
+        channels = 3
+        bytesPerChannel = 4
+        mode = 'RGB'
+    elif magic == 'PX':
+        channels = 4
+        bytesPerChannel = 4
         mode = 'RGB'
     else:
         raise Exception('Unsupported magic `%s`' % magic)
@@ -147,12 +161,35 @@ def read_pnm(stream):
         line = stream.readline()
     width, height = map(int, line.strip().split())
     maximum = int(stream.readline().strip())
-    assert maximum == 255
-    data = stream.read(height * width * channels)
+    if bytesPerChannel == 1:
+        assert maximum == 255
+    else:
+        assert maximum == 1
+    data = stream.read(height * width * channels * bytesPerChannel)
+    if bytesPerChannel == 4:
+        # Image magic only supports single channel floating point images, so
+        # represent the image as numpy arrays
+
+        import numpy
+        pixels = numpy.fromstring(data, dtype=numpy.float32)
+        pixels.resize((height, width, channels))
+        return pixels, comment
+
     image = Image.frombuffer(mode, (width, height), data, 'raw', mode, 0, 1)
     return image, comment
 
 
+def dumpNumpyImage(output, pixels):
+    height, width, channels = pixels.shape
+    for y in range(height):
+        output.write('  ')
+        for x in range(width):
+            for c in range(channels):
+                output.write('%0.9g,' % pixels[y, x, c])
+            output.write('  ')
+        output.write('\n')
+
+
 def parse_env(optparser, entries):
     '''Translate a list of NAME=VALUE entries into an environment dictionary.'''
 
@@ -272,8 +309,25 @@ def main():
                 callNo = refCallNo
 
                 # Compare the two images
-                comparer = Comparer(refImage, srcImage)
-                precision = comparer.precision()
+                if isinstance(refImage, Image.Image) and isinstance(srcImage, Image.Image):
+                    # Using PIL
+                    numpyImages = False
+                    comparer = Comparer(refImage, srcImage)
+                    precision = comparer.precision()
+                else:
+                    # Using numpy (for floating point images)
+                    # TODO: drop PIL when numpy path becomes general enough
+                    import numpy
+                    assert not isinstance(refImage, Image.Image)
+                    assert not isinstance(srcImage, Image.Image)
+                    numpyImages = True
+                    assert refImage.shape == srcImage.shape
+                    diffImage = numpy.square(srcImage - refImage)
+                    match = numpy.all(diffImage == 0)
+                    if match:
+                        precision = 24
+                    else:
+                        precision = 0
 
                 mismatch = precision < options.threshold
 
@@ -285,7 +339,11 @@ def main():
                     highligher.normal()
 
                 if mismatch:
-                    if options.diff_prefix:
+                    if numpyImages:
+                        dumpNumpyImage(output, refImage)
+                        output.write("->\n")
+                        dumpNumpyImage(output, srcImage)
+                    if options.diff_prefix and not numpyImages:
                         prefix = os.path.join(options.diff_prefix, '%010u' % callNo)
                         prefix_dir = os.path.dirname(prefix)
                         if not os.path.isdir(prefix_dir):