added rendertest/ directory
[swftools.git] / rendertest / testpdfs.py
diff --git a/rendertest/testpdfs.py b/rendertest/testpdfs.py
new file mode 100644 (file)
index 0000000..cb6344e
--- /dev/null
@@ -0,0 +1,359 @@
+import Image
+import ImageChops
+import ImageFilter
+import sys
+import os
+import traceback
+from athana import getTALstr
+import random
+import md5
+
+filenames = []
+directories = ["pdfs"]
+
+SWFRENDER="swfrender"
+PDFTOPPM="pdftoppm"
+CONVERT="convert"
+PDF2SWF="pdf2swf"
+
+#COMPARE=["xpdf", PDF2SWF+" -s poly2bitmap"]
+#OUTPUTDIR = "results.poly2bitmap/"
+
+COMPARE=["xpdf", PDF2SWF+" -s convertgradients"]
+OUTPUTDIR = "results.pdf2swf/"
+
+#COMPARE=[PDF2SWF, PDF2SWF+" --flatten"]
+#OUTPUTDIR = "results.flatten/"
+
+counter = 1
+
+def randstr():
+    return md5.md5(str(random.random())).hexdigest()[0:8]
+
+def unlink(file):
+    try:
+        os.unlink(file)
+    except:
+        pass
+
+def system(command):
+    if ">" not in command:
+        if os.system(command + " > /tmp/log.txt 2>&1") & 0xff00:
+            error = open("/tmp/log.txt", "rb").read()
+            print error
+            return error
+    else:
+        if os.system(command) & 0xff00:
+            return "Unknown error in "+command
+
+class ConversionError:
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return self.msg
+
+class TooComplexError:
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return self.msg
+
+class BadMatch:
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return self.msg
+
+def formatException():
+    s = "Exception "+str(sys.exc_info()[0])
+    info = sys.exc_info()[1]
+    if info:
+        s += " "+str(info)
+    s += "\n"
+    for l in traceback.extract_tb(sys.exc_info()[2]):
+        s += "  File \"%s\", line %d, in %s\n" % (l[0],l[1],l[2])
+        s += "    %s\n" % l[3]
+    return s
+
+
+class PDFPage:
+    def __init__(self, filename, page, width, height):
+        self.filename = filename
+        self.page = page
+        self.rating = None
+        self.message = None
+        self.htmlmessage = None
+        self.file1 = None
+        self.file2 = None
+        self.file12 = None
+        self.html12 = None
+        self.htmldiff = None
+        self.width,self.height = width,height
+
+    def runtools(self, filename, page, file1, file2, file12):
+
+        badness = 0.0
+
+        if COMPARE[0] == "xpdf":
+            unlink("/tmp/test-%06d.ppm" % page)
+            error = system(PDFTOPPM + " -r 72 -f %d -l %d '%s' /tmp/test" % (page, page, filename))
+            if error and "supports 65536" in error:
+                raise TooComplexError(error)
+            if error:
+                raise ConversionError(error)
+            unlink(file2)
+            error = system(CONVERT + " /tmp/test-%06d.ppm  %s" % (page, file2))
+            if error:
+                raise ConversionError(error)
+            unlink("/tmp/test-%06d.ppm" % page)
+        else:
+            unlink("/tmp/test.swf")
+            unlink("svp.ps")
+            error = system(COMPARE[0]+ " -Q 300 -p%d '%s' -o /tmp/test.swf" % (page, filename))
+            #system("mv svp.ps %s.ps" % randstr())
+            if error and "supports 65536" in error:
+                raise TooComplexError(error)
+            if error:
+                raise ConversionError(error)
+            unlink(file2)
+            error = system(SWFRENDER + " /tmp/test.swf -o %s" % file2)
+            if error:
+                raise ConversionError(error)
+            unlink("/tmp/test.swf")
+        
+        unlink("/tmp/test.swf")
+        error = system(COMPARE[1]+ " -Q 300 -p%d '%s' -o /tmp/test.swf" % (page, filename))
+        if error:
+            raise ConversionError(error)
+        unlink(file1)
+        error = system(SWFRENDER + " /tmp/test.swf -o %s" % file1)
+        if error:
+            raise ConversionError(error)
+        unlink("/tmp/test.swf")
+
+        unlink(file12)
+        pic1 = Image.open(file1)
+        pic1.load()
+        self.width1 = pic1.size[0]
+        self.height1 = pic1.size[1]
+        
+        pic2 = Image.open(file2)
+        pic2.load()
+        self.width2 = pic2.size[0]
+        self.height2 = pic2.size[1]
+
+        if abs(self.width1-self.width2)>5 or abs(self.height1!=self.height2)>5:
+            badness += 65536*abs(self.width2-self.width1)*max(self.height1,self.height2)+65536*abs(self.height2-self.height1)*max(self.width1,self.width2)
+
+        minx = min(self.width1,self.width2)
+        miny = min(self.height1,self.height2)
+
+        pic1 = pic1.crop((0,0,minx,miny))
+        pic1 = pic1.convert("RGB")
+        pic1 = pic1.filter(ImageFilter.BLUR)
+        pic2 = pic2.crop((0,0,minx,miny))
+        pic2 = pic2.convert("RGB")
+        pic2 = pic2.filter(ImageFilter.BLUR)
+
+        diffimage = ImageChops.difference(pic1,pic2)
+        diffimage.save(file12, "PNG")
+        
+        # compute quadratical difference
+        diff = diffimage.histogram()
+        for i in range(1,128):
+            badness += (diff[i] + diff[256-i])*float(i*i)
+            badness += (diff[256+i] + diff[256+256-i])*float(i*i)
+            badness += (diff[512+i] + diff[512+256-i])*float(i*i)
+
+        badness /= (minx*miny)*3
+
+        return badness
+
+    def compare(self):
+        try:
+            global counter
+            self.file1 = str(counter) + ".png"
+            counter = counter + 1
+            self.file2 = str(counter) + ".png"
+            counter = counter + 1
+            self.file12 = str(counter) + ".png"
+            counter = counter + 1
+            self.rating = self.runtools(self.filename, self.page, OUTPUTDIR + self.file1, OUTPUTDIR + self.file2, OUTPUTDIR + self.file12)
+        except BadMatch:
+            self.rating = 65534.0
+            self.message = formatException()
+            print self.message
+        except ConversionError:
+            self.rating = 65535.0
+            self.message = formatException()
+            print self.message
+        except TooComplexError:
+            self.rating = 65536.0
+            self.message = formatException()
+            print self.message
+        except:
+            self.rating = 65537.0
+            self.message = formatException()
+            print self.message
+
+    def getsizes(self):
+        if self.message:
+            return ""
+        if abs(self.width1 - self.width2) > 5 or \
+           abs(self.height1 - self.height2) > 5:
+               return '<font color="red">%dx%d <-> %dx%d</font>' % (self.width1, self.height1, self.width2, self.height2)
+        else:
+               return '%dx%d,%dx%d' % (self.width1, self.height1, self.width2, self.height2)
+
+    def generatehtml(self):
+        global OUTPUTDIR
+        global counter
+        self.html12 = str(counter) + ".html"
+        counter = counter + 1
+        self.htmldiff = str(counter) + ".html"
+        counter = counter + 1
+        fi = open(OUTPUTDIR + self.html12, "wb")
+        fi.write(getTALstr("""
+<html><head></head>
+<body>
+<tal:block tal:replace="python:'File: '+self.filename"/><br>
+<tal:block tal:replace="python:'Page: '+str(self.page)"/><br>
+<tal:block tal:replace="python:'Rating: '+str(self.rating)"/><br>
+<pre tal:condition="python:self.message" tal:replace="python:'Message: '+str(self.message)"/><br>
+<hr>
+<table cellspacing="0" cellpadding="0">
+<tr><td><img tal:attributes="src python:self.file1"/></td><td><img tal:attributes="src python:self.file2"/></td></tr>
+<tr><td>pdf2swf Version</td><td>pdftoppm Version</td></tr>
+</table>
+<hr>
+</body>
+</html>""", {"self": self}))
+        fi.close()
+        
+        fi = open(OUTPUTDIR + self.htmldiff, "wb")
+        fi.write(getTALstr("""
+<html><head></head>
+<body>
+<tal:block tal:replace="python:'File: '+self.filename"/><br>
+<tal:block tal:replace="python:'Page: '+str(self.page)"/><br>
+<tal:block tal:replace="python:'Rating: '+str(self.rating)"/><br>
+<pre tal:condition="python:self.message" tal:replace="python:'Message: '+str(self.message)"/><br>
+<hr>
+<img tal:attributes="src python:self.file12"/>
+<hr>
+</body>
+</html>""", {"self": self}))
+        fi.close()
+        
+        if self.message:
+            self.htmlmessage = str(counter) + ".html"
+            counter = counter + 1
+            fi = open(OUTPUTDIR + self.htmlmessage, "wb")
+            fi.write(getTALstr("""
+<html><head></head>
+<body>
+<pre tal:content="raw python:self.message">
+</pre>
+</body>
+</html>""", {"self": self}))
+            fi.close()
+        
+
+
+def compare_pages(page1,page2):
+    if page1.rating < page2.rating:
+        return 1
+    elif page1.rating > page2.rating:
+        return -1
+    else:
+        return 0
+
+
+def add_directory(directory):
+    if not os.path.isdir(directory):
+        print "bad directory:",directory
+        return
+    for file in os.listdir(directory):
+        global filenames
+        filename = os.path.join(directory, file)
+        if file.lower().endswith(".pdf"):
+            filenames += [filename]
+            print "+",filename
+        elif os.path.isdir(filename):
+            add_directory(filename)
+
+pages = []
+try:
+    os.mkdir(OUTPUTDIR)
+except: pass
+
+for file in filenames:
+    print "+",file
+
+for dir in directories:
+    add_directory(dir)
+
+for filename in filenames:
+    try:
+        unlink("/tmp/test.txt")
+        error = system(PDF2SWF + " -I %s -o /tmp/test.txt" % filename)
+        if error:
+            raise ConversionError(error)
+        fi = open("/tmp/test.txt", "rb")
+        for line in fi.readlines():
+            p = {}
+            for param in line.split(" "):
+                key,value = param.split("=")
+                p[key] = value
+            page = int(p["page"])
+            width = int(float(p["width"]))
+            height = int(float(p["height"]))
+            print filename, page, "%dx%d" % (width, height)
+            pdfpage = PDFPage(filename, page, width, height)
+            pdfpage.compare()
+
+            if width < 2000 and height < 2000:
+                pages += [pdfpage]
+
+            # only consider the first 3 pages
+            if page > 3:
+                break
+        fi.close()
+    except KeyboardInterrupt:
+        break
+    except:
+        pdfpage = PDFPage(filename, -1, -1, -1)
+        pdfpage.rating = 65536.0
+        pdfpage.message = formatException()
+        pages += [pdfpage]
+
+pages.sort(compare_pages)
+
+position = 1
+for page in pages:
+    page.generatehtml()
+    page.position = position
+    position = position + 1
+
+fi = open(OUTPUTDIR + "index.html", "wb")
+fi.write(getTALstr("""<html>
+<head></head>
+<body>
+<table border="1"><tr><th>Position</th><th>Rating</th><th>File</th><th>Size</th><th>Page</th><th>Images</th><th>Diff</th><th>Further Info</th></tr>
+<tal:block tal:repeat="page pages">
+<tr>
+<td tal:content="python:page.position"/>
+<td tal:content="python:page.rating"/>
+<td tal:content="python:page.filename"/>
+<td tal:content="raw python:page.getsizes()"/>
+<td tal:content="python:page.page"/>
+<td><a tal:attributes="href python:page.html12">Side by Side</a></td>
+<td><a tal:attributes="href python:page.htmldiff">Difference</a></td>
+<td><a tal:condition="python:page.message" tal:attributes="href python:page.htmlmessage">Error message</a></td>
+</tr>
+</tal:block>
+</table>
+</body>
+</html>""", {"pages": pages}))
+fi.close()
+