Code

add QR Code rendering extension
authord <d@d-desktop>
Tue, 9 Nov 2010 04:08:25 +0000 (00:08 -0400)
committerd <d@d-desktop>
Tue, 9 Nov 2010 04:08:25 +0000 (00:08 -0400)
share/extensions/Makefile.am
share/extensions/render_barcode_qrcode.inx [new file with mode: 0644]
share/extensions/render_barcode_qrcode.py [new file with mode: 0644]

index d77ac1fec79e651f416bcefd7b6e82fcc6c96104..f735f2ff249b7dfb4fcc59d0023cba25018f6564 100644 (file)
@@ -118,6 +118,7 @@ extensions = \
        restack.py \
        render_barcode.py \
        render_barcode_datamatrix.py \
+       render_barcode_qrcode.py \
        render_alphabetsoup.py \
        render_alphabetsoup_config.py \
        rtree.py \
@@ -278,6 +279,7 @@ modules = \
        radiusrand.inx \
        render_barcode.inx \
        render_barcode_datamatrix.inx \
+       render_barcode_qrcode.inx \
        render_alphabetsoup.inx \
        replace_font.inx \
        restack.inx \
diff --git a/share/extensions/render_barcode_qrcode.inx b/share/extensions/render_barcode_qrcode.inx
new file mode 100644 (file)
index 0000000..b0085f6
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+       <_name>Barcode - QR Code</_name>
+       <id>org.inkscape.qrcode</id>
+       <dependency type="executable" location="extensions">render_barcode_qrcode.py</dependency>
+       <dependency type="executable" location="extensions">inkex.py</dependency>
+     <_param name="generalhint" type="description" xml:space="preserve">See http://www.denso-wave.com/qrcode/index-e.html for details</_param>
+       <param name="text" type="string" _gui-text="Text:">www.inkscape.org</param>
+     <param name="typenumber" type="enum" _gui-text="Size, in unit squares:">
+        <_item value="0">Auto</_item>
+        <item value="1">21x21</item>
+        <item value="2">25x25</item>
+        <item value="3">29x29</item>
+        <item value="4">33x33</item>
+        <item value="5">37x37</item>
+        <item value="6">41x41</item>
+        <item value="7">45x45</item>
+        <item value="8">49x49</item>
+        <item value="9">53x53</item>
+        <item value="10">57x37</item>
+        <item value="11">61x61</item>
+        <item value="12">65x65</item>
+        <item value="13">69x69</item>
+        <item value="14">73x73</item>
+        <item value="15">77x77</item>
+        <item value="16">81x81</item>
+        <item value="17">85x85</item>
+        <item value="18">89x89</item>
+        <item value="19">93x93</item>
+        <item value="20">97x97</item>
+        <item value="21">101x101</item>
+        <item value="22">105x105</item>
+        <item value="23">109x109</item>
+        <item value="24">113x113</item>
+        <item value="25">117x117</item>
+        <item value="26">121x121</item>
+        <item value="27">125x125</item>
+        <item value="28">129x129</item>
+        <item value="29">133x133</item>
+        <item value="30">137x137</item>
+        <item value="31">141x141</item>
+        <item value="32">145x145</item>
+        <item value="33">149x149</item>
+        <item value="34">153x153</item>
+        <item value="35">157x157</item>
+        <item value="36">161x161</item>
+        <item value="37">165x165</item>
+        <item value="38">169x169</item>
+        <item value="39">173x173</item>
+        <item value="40">177x177</item>
+     </param>
+     <_param name="sizehint" type="description" xml:space="preserve">With "Auto", the size of the barcode depends on the length of the text and the error correction level</_param>
+     <param name="correctionlevel" type="enum" _gui-text="Error correction level:">
+        <_item value="1">L (Approx. 7%)</_item>
+        <_item value="0">M (Approx. 15%)</_item>
+        <_item value="3">Q (Approx. 25%)</_item>
+        <_item value="2">H (Approx. 30%)</_item>
+     </param>  
+       <param name="modulesize" type="float" min="0" max="1000" _gui-text="Square size (px):">4</param>
+       <effect>
+               <object-type>all</object-type>
+               <effects-menu>
+                       <submenu _name="Render"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">render_barcode_qrcode.py</command>
+       </script>
+</inkscape-extension>
diff --git a/share/extensions/render_barcode_qrcode.py b/share/extensions/render_barcode_qrcode.py
new file mode 100644 (file)
index 0000000..7b6759c
--- /dev/null
@@ -0,0 +1,1057 @@
+import math, sys\r
+import inkex\r
+\r
+#QRCode for Python\r
+#\r
+#Ported from the Javascript library by Sam Curren\r
+#\r
+#QRCode for Javascript\r
+#http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js\r
+#\r
+#Copyright (c) 2009 Kazuhiko Arase\r
+#\r
+#URL: http://www.d-project.com/\r
+#\r
+#Licensed under the MIT license:\r
+#   http://www.opensource.org/licenses/mit-license.php\r
+#\r
+# The word "QR Code" is registered trademark of\r
+# DENSO WAVE INCORPORATED\r
+#   http://www.denso-wave.com/qrcode/faqpatent-e.html\r
+\r
+\r
+class QR8bitByte:\r
+\r
+    def __init__(self, data):\r
+        self.mode = QRMode.MODE_8BIT_BYTE\r
+        self.data = data\r
+\r
+    def getLength(self):\r
+        return len(self.data)\r
+\r
+    def write(self, buffer):\r
+        for i in range(len(self.data)):\r
+            #// not JIS ...\r
+            buffer.put(ord(self.data[i]), 8)\r
+    def __repr__(self):\r
+        return self.data\r
+\r
+class QRCode:\r
+    def __init__(self, typeNumber, errorCorrectLevel):\r
+        self.typeNumber = typeNumber\r
+        self.errorCorrectLevel = errorCorrectLevel\r
+        self.modules = None\r
+        self.moduleCount = 0\r
+        self.dataCache = None\r
+        self.dataList = []\r
+    def addData(self, data):\r
+        newData = QR8bitByte(data)\r
+        self.dataList.append(newData)\r
+        self.dataCache = None\r
+    def isDark(self, row, col):\r
+        if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col):\r
+            raise Exception("%s,%s - %s" % (row, col, self.moduleCount))\r
+        return self.modules[row][col]\r
+    def getModuleCount(self):\r
+        return self.moduleCount\r
+    def make(self):\r
+        self.makeImpl(False, self.getBestMaskPattern() )\r
+    def makeImpl(self, test, maskPattern):\r
+\r
+        if self.typeNumber == 0:\r
+            self.typeNumber = QRCode.autoNumber(self.errorCorrectLevel, self.dataList)\r
+        self.moduleCount = self.typeNumber * 4 + 17\r
+        self.modules = [None for x in range(self.moduleCount)]\r
+\r
+        for row in range(self.moduleCount):\r
+\r
+            self.modules[row] = [None for x in range(self.moduleCount)]\r
+\r
+            for col in range(self.moduleCount):\r
+                self.modules[row][col] = None #//(col + row) % 3;\r
+\r
+        self.setupPositionProbePattern(0, 0)\r
+        self.setupPositionProbePattern(self.moduleCount - 7, 0)\r
+        self.setupPositionProbePattern(0, self.moduleCount - 7)\r
+        self.setupPositionAdjustPattern()\r
+        self.setupTimingPattern()\r
+        self.setupTypeInfo(test, maskPattern)\r
+\r
+        if (self.typeNumber >= 7):\r
+            self.setupTypeNumber(test)\r
+\r
+        if (self.dataCache == None):\r
+            self.dataCache = QRCode.createData(self.typeNumber, self.errorCorrectLevel, self.dataList)\r
+        self.mapData(self.dataCache, maskPattern)\r
+\r
+    def setupPositionProbePattern(self, row, col):\r
+\r
+        for r in range(-1, 8):\r
+\r
+            if (row + r <= -1 or self.moduleCount <= row + r): continue\r
+\r
+            for c in range(-1, 8):\r
+\r
+                if (col + c <= -1 or self.moduleCount <= col + c): continue\r
+\r
+                if ( (0 <= r and r <= 6 and (c == 0 or c == 6) )\r
+                        or (0 <= c and c <= 6 and (r == 0 or r == 6) )\r
+                        or (2 <= r and r <= 4 and 2 <= c and c <= 4) ):\r
+                    self.modules[row + r][col + c] = True;\r
+                else:\r
+                    self.modules[row + r][col + c] = False;\r
+\r
+    def getBestMaskPattern(self):\r
+\r
+        minLostPoint = 0\r
+        pattern = 0\r
+\r
+        for i in range(8):\r
+\r
+            self.makeImpl(True, i);\r
+\r
+            lostPoint = QRUtil.getLostPoint(self);\r
+\r
+            if (i == 0 or minLostPoint > lostPoint):\r
+                minLostPoint = lostPoint\r
+                pattern = i\r
+\r
+        return pattern\r
+\r
+    def makeSVG(self, grp, boxsize):\r
+        pixelsize = self.getModuleCount() * boxsize\r
+\r
+        for r in range(self.getModuleCount()):\r
+            for c in range(self.getModuleCount()):\r
+                if (self.isDark(r, c) ):\r
+                    x = c * boxsize\r
+                    y = r * boxsize\r
+                    rect = inkex.etree.SubElement(grp, inkex.addNS('rect', 'svg'))\r
+                    rect.set('x', str(x))\r
+                    rect.set('y', str(y))\r
+                    rect.set('width', str(boxsize))\r
+                    rect.set('height', str(boxsize))\r
+                    rect.set('style', 'fill:black;stroke:none')\r
+\r
+    def setupTimingPattern(self):\r
+\r
+        for r in range(8, self.moduleCount - 8):\r
+            if (self.modules[r][6] != None):\r
+                continue\r
+            self.modules[r][6] = (r % 2 == 0)\r
+\r
+        for c in range(8, self.moduleCount - 8):\r
+            if (self.modules[6][c] != None):\r
+                continue\r
+            self.modules[6][c] = (c % 2 == 0)\r
+\r
+    def setupPositionAdjustPattern(self):\r
+\r
+        pos = QRUtil.getPatternPosition(self.typeNumber)\r
+\r
+        for i in range(len(pos)):\r
+\r
+            for j in range(len(pos)):\r
+\r
+                row = pos[i]\r
+                col = pos[j]\r
+\r
+                if (self.modules[row][col] != None):\r
+                    continue\r
+\r
+                for r in range(-2, 3):\r
+\r
+                    for c in range(-2, 3):\r
+\r
+                        if (r == -2 or r == 2 or c == -2 or c == 2 or (r == 0 and c == 0) ):\r
+                            self.modules[row + r][col + c] = True\r
+                        else:\r
+                            self.modules[row + r][col + c] = False\r
+\r
+    def setupTypeNumber(self, test):\r
+\r
+        bits = QRUtil.getBCHTypeNumber(self.typeNumber)\r
+\r
+        for i in range(18):\r
+            mod = (not test and ( (bits >> i) & 1) == 1)\r
+            self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = mod;\r
+\r
+        for i in range(18):\r
+            mod = (not test and ( (bits >> i) & 1) == 1)\r
+            self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = mod;\r
+\r
+    def setupTypeInfo(self, test, maskPattern):\r
+\r
+        data = (self.errorCorrectLevel << 3) | maskPattern\r
+        bits = QRUtil.getBCHTypeInfo(data)\r
+\r
+        #// vertical\r
+        for i in range(15):\r
+\r
+            mod = (not test and ( (bits >> i) & 1) == 1)\r
+\r
+            if (i < 6):\r
+                self.modules[i][8] = mod\r
+            elif (i < 8):\r
+                self.modules[i + 1][8] = mod\r
+            else:\r
+                self.modules[self.moduleCount - 15 + i][8] = mod\r
+\r
+        #// horizontal\r
+        for i in range(15):\r
+\r
+            mod = (not test and ( (bits >> i) & 1) == 1);\r
+\r
+            if (i < 8):\r
+                self.modules[8][self.moduleCount - i - 1] = mod\r
+            elif (i < 9):\r
+                self.modules[8][15 - i - 1 + 1] = mod\r
+            else:\r
+                self.modules[8][15 - i - 1] = mod\r
+\r
+        #// fixed module\r
+        self.modules[self.moduleCount - 8][8] = (not test)\r
+\r
+    def mapData(self, data, maskPattern):\r
+\r
+        inc = -1\r
+        row = self.moduleCount - 1\r
+        bitIndex = 7\r
+        byteIndex = 0\r
+\r
+        for col in range(self.moduleCount - 1, 0, -2):\r
+\r
+            if (col == 6): col-=1\r
+\r
+            while (True):\r
+\r
+                for c in range(2):\r
+\r
+                    if (self.modules[row][col - c] == None):\r
+\r
+                        dark = False\r
+\r
+                        if (byteIndex < len(data)):\r
+                            dark = ( ( (data[byteIndex] >> bitIndex) & 1) == 1)\r
+\r
+                        mask = QRUtil.getMask(maskPattern, row, col - c)\r
+\r
+                        if (mask):\r
+                            dark = not dark\r
+\r
+                        self.modules[row][col - c] = dark\r
+                        bitIndex-=1\r
+\r
+                        if (bitIndex == -1):\r
+                            byteIndex+=1\r
+                            bitIndex = 7\r
+\r
+                row += inc\r
+\r
+                if (row < 0 or self.moduleCount <= row):\r
+                    row -= inc\r
+                    inc = -inc\r
+                    break\r
+    PAD0 = 0xEC\r
+    PAD1 = 0x11\r
+\r
+    @staticmethod\r
+    def autoNumber(errorCorrectLevel, dataList):\r
+\r
+        for tn in range (1, 40):\r
+            \r
+            rsBlocks = QRRSBlock.getRSBlocks(tn, errorCorrectLevel)\r
+\r
+            buffer = QRBitBuffer();\r
+\r
+            for i in range(len(dataList)):\r
+                data = dataList[i]\r
+                buffer.put(data.mode, 4)\r
+                buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, tn) )\r
+                data.write(buffer)\r
+\r
+            #// calc num max data.\r
+            totalDataCount = 0;\r
+            for i in range(len(rsBlocks)):\r
+                totalDataCount += rsBlocks[i].dataCount\r
+\r
+            if (buffer.getLengthInBits() <= totalDataCount * 8):\r
+                return tn\r
+\r
+        inkex.errormsg("Even the largest size won't take this much data ("\r
+            + str(buffer.getLengthInBits())\r
+            + ">"\r
+            +  str(totalDataCount * 8)\r
+            + ")")\r
+        sys.exit()\r
+        \r
+\r
+\r
+    @staticmethod\r
+    def createData(typeNumber, errorCorrectLevel, dataList):\r
+\r
+        rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel)\r
+\r
+        buffer = QRBitBuffer();\r
+\r
+        for i in range(len(dataList)):\r
+            data = dataList[i]\r
+            buffer.put(data.mode, 4)\r
+            buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) )\r
+            data.write(buffer)\r
+\r
+        #// calc num max data.\r
+        totalDataCount = 0;\r
+        for i in range(len(rsBlocks)):\r
+            totalDataCount += rsBlocks[i].dataCount\r
+\r
+        if (buffer.getLengthInBits() > totalDataCount * 8):\r
+            inkex.errormsg("Text is too long for this size ("\r
+                + str(buffer.getLengthInBits())\r
+                + ">"\r
+                +  str(totalDataCount * 8)\r
+                + ")")\r
+            sys.exit()\r
+\r
+        #// end code\r
+        if (buffer.getLengthInBits() + 4 <= totalDataCount * 8):\r
+            buffer.put(0, 4)\r
+\r
+        #// padding\r
+        while (buffer.getLengthInBits() % 8 != 0):\r
+            buffer.putBit(False)\r
+\r
+        #// padding\r
+        while (True):\r
+\r
+            if (buffer.getLengthInBits() >= totalDataCount * 8):\r
+                break\r
+            buffer.put(QRCode.PAD0, 8)\r
+\r
+            if (buffer.getLengthInBits() >= totalDataCount * 8):\r
+                break\r
+            buffer.put(QRCode.PAD1, 8)\r
+\r
+        return QRCode.createBytes(buffer, rsBlocks)\r
+\r
+    @staticmethod\r
+    def createBytes(buffer, rsBlocks):\r
+\r
+        offset = 0\r
+\r
+        maxDcCount = 0\r
+        maxEcCount = 0\r
+\r
+        dcdata = [0 for x in range(len(rsBlocks))]\r
+        ecdata = [0 for x in range(len(rsBlocks))]\r
+\r
+        for r in range(len(rsBlocks)):\r
+\r
+            dcCount = rsBlocks[r].dataCount\r
+            ecCount = rsBlocks[r].totalCount - dcCount\r
+\r
+            maxDcCount = max(maxDcCount, dcCount)\r
+            maxEcCount = max(maxEcCount, ecCount)\r
+\r
+            dcdata[r] = [0 for x in range(dcCount)]\r
+\r
+            for i in range(len(dcdata[r])):\r
+                dcdata[r][i] = 0xff & buffer.buffer[i + offset]\r
+            offset += dcCount\r
+\r
+            rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount)\r
+            rawPoly = QRPolynomial(dcdata[r], rsPoly.getLength() - 1)\r
+\r
+            modPoly = rawPoly.mod(rsPoly)\r
+            ecdata[r] = [0 for x in range(rsPoly.getLength()-1)]\r
+            for i in range(len(ecdata[r])):\r
+                modIndex = i + modPoly.getLength() - len(ecdata[r])\r
+                if (modIndex >= 0):\r
+                    ecdata[r][i] = modPoly.get(modIndex)\r
+                else:\r
+                    ecdata[r][i] = 0\r
+\r
+        totalCodeCount = 0\r
+        for i in range(len(rsBlocks)):\r
+            totalCodeCount += rsBlocks[i].totalCount\r
+\r
+        data = [None for x in range(totalCodeCount)]\r
+        index = 0\r
+\r
+        for i in range(maxDcCount):\r
+            for r in range(len(rsBlocks)):\r
+                if (i < len(dcdata[r])):\r
+                    data[index] = dcdata[r][i]\r
+                    index+=1\r
+\r
+        for i in range(maxEcCount):\r
+            for r in range(len(rsBlocks)):\r
+                if (i < len(ecdata[r])):\r
+                    data[index] = ecdata[r][i]\r
+                    index+=1\r
+\r
+        return data\r
+\r
+\r
+class QRMode:\r
+    MODE_NUMBER = 1 << 0\r
+    MODE_ALPHA_NUM = 1 << 1\r
+    MODE_8BIT_BYTE = 1 << 2\r
+    MODE_KANJI = 1 << 3\r
+\r
+class QRErrorCorrectLevel:\r
+    L = 1\r
+    M = 0\r
+    Q = 3\r
+    H = 2\r
+\r
+class QRMaskPattern:\r
+    PATTERN000 = 0\r
+    PATTERN001 = 1\r
+    PATTERN010 = 2\r
+    PATTERN011 = 3\r
+    PATTERN100 = 4\r
+    PATTERN101 = 5\r
+    PATTERN110 = 6\r
+    PATTERN111 = 7\r
+\r
+class QRUtil(object):\r
+    PATTERN_POSITION_TABLE = [\r
+        [],\r
+        [6, 18],\r
+        [6, 22],\r
+        [6, 26],\r
+        [6, 30],\r
+        [6, 34],\r
+        [6, 22, 38],\r
+        [6, 24, 42],\r
+        [6, 26, 46],\r
+        [6, 28, 50],\r
+        [6, 30, 54],\r
+        [6, 32, 58],\r
+        [6, 34, 62],\r
+        [6, 26, 46, 66],\r
+        [6, 26, 48, 70],\r
+        [6, 26, 50, 74],\r
+        [6, 30, 54, 78],\r
+        [6, 30, 56, 82],\r
+        [6, 30, 58, 86],\r
+        [6, 34, 62, 90],\r
+        [6, 28, 50, 72, 94],\r
+        [6, 26, 50, 74, 98],\r
+        [6, 30, 54, 78, 102],\r
+        [6, 28, 54, 80, 106],\r
+        [6, 32, 58, 84, 110],\r
+        [6, 30, 58, 86, 114],\r
+        [6, 34, 62, 90, 118],\r
+        [6, 26, 50, 74, 98, 122],\r
+        [6, 30, 54, 78, 102, 126],\r
+        [6, 26, 52, 78, 104, 130],\r
+        [6, 30, 56, 82, 108, 134],\r
+        [6, 34, 60, 86, 112, 138],\r
+        [6, 30, 58, 86, 114, 142],\r
+        [6, 34, 62, 90, 118, 146],\r
+        [6, 30, 54, 78, 102, 126, 150],\r
+        [6, 24, 50, 76, 102, 128, 154],\r
+        [6, 28, 54, 80, 106, 132, 158],\r
+        [6, 32, 58, 84, 110, 136, 162],\r
+        [6, 26, 54, 82, 110, 138, 166],\r
+        [6, 30, 58, 86, 114, 142, 170]\r
+    ]\r
+\r
+    G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0)\r
+    G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)\r
+    G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)\r
+\r
+    @staticmethod\r
+    def getBCHTypeInfo(data):\r
+        d = data << 10;\r
+        while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0):\r
+            d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) )\r
+\r
+        return ( (data << 10) | d) ^ QRUtil.G15_MASK\r
+    @staticmethod\r
+    def getBCHTypeNumber(data):\r
+        d = data << 12;\r
+        while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0):\r
+            d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) )\r
+        return (data << 12) | d\r
+    @staticmethod\r
+    def getBCHDigit(data):\r
+        digit = 0;\r
+        while (data != 0):\r
+            digit += 1\r
+            data >>= 1\r
+        return digit\r
+    @staticmethod\r
+    def getPatternPosition(typeNumber):\r
+        return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]\r
+    @staticmethod\r
+    def getMask(maskPattern, i, j):\r
+        if maskPattern == QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN001 : return i % 2 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN010 : return j % 3 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN100 : return (math.floor(i / 2) + math.floor(j / 3) ) % 2 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0\r
+        if maskPattern == QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0\r
+        raise Exception("bad maskPattern:" + maskPattern);\r
+    @staticmethod\r
+    def getErrorCorrectPolynomial(errorCorrectLength):\r
+        a = QRPolynomial([1], 0);\r
+        for i in range(errorCorrectLength):\r
+            a = a.multiply(QRPolynomial([1, QRMath.gexp(i)], 0) )\r
+        return a\r
+    @staticmethod\r
+    def getLengthInBits(mode, type):\r
+\r
+        if 1 <= type and type < 10:\r
+\r
+            #// 1 - 9\r
+\r
+            if mode == QRMode.MODE_NUMBER     : return 10\r
+            if mode == QRMode.MODE_ALPHA_NUM     : return 9\r
+            if mode == QRMode.MODE_8BIT_BYTE    : return 8\r
+            if mode == QRMode.MODE_KANJI      : return 8\r
+            raise Exception("mode:" + mode)\r
+\r
+        elif (type < 27):\r
+\r
+            #// 10 - 26\r
+\r
+            if mode == QRMode.MODE_NUMBER     : return 12\r
+            if mode == QRMode.MODE_ALPHA_NUM     : return 11\r
+            if mode == QRMode.MODE_8BIT_BYTE    : return 16\r
+            if mode == QRMode.MODE_KANJI      : return 10\r
+            raise Exception("mode:" + mode)\r
+\r
+        elif (type < 41):\r
+\r
+            #// 27 - 40\r
+\r
+            if mode == QRMode.MODE_NUMBER     : return 14\r
+            if mode == QRMode.MODE_ALPHA_NUM    : return 13\r
+            if mode == QRMode.MODE_8BIT_BYTE    : return 16\r
+            if mode == QRMode.MODE_KANJI      : return 12\r
+            raise Exception("mode:" + mode)\r
+\r
+        else:\r
+            raise Exception("type:" + type)\r
+    @staticmethod\r
+    def getLostPoint(qrCode):\r
+\r
+        moduleCount = qrCode.getModuleCount();\r
+\r
+        lostPoint = 0;\r
+\r
+        #// LEVEL1\r
+\r
+        for row in range(moduleCount):\r
+\r
+            for col in range(moduleCount):\r
+\r
+                sameCount = 0;\r
+                dark = qrCode.isDark(row, col);\r
+\r
+                for r in range(-1, 2):\r
+\r
+                    if (row + r < 0 or moduleCount <= row + r):\r
+                        continue\r
+\r
+                    for c in range(-1, 2):\r
+\r
+                        if (col + c < 0 or moduleCount <= col + c):\r
+                            continue\r
+                        if (r == 0 and c == 0):\r
+                            continue\r
+\r
+                        if (dark == qrCode.isDark(row + r, col + c) ):\r
+                            sameCount+=1\r
+                if (sameCount > 5):\r
+                    lostPoint += (3 + sameCount - 5)\r
+\r
+        #// LEVEL2\r
+\r
+        for row in range(moduleCount - 1):\r
+            for col in range(moduleCount - 1):\r
+                count = 0;\r
+                if (qrCode.isDark(row,     col    ) ): count+=1\r
+                if (qrCode.isDark(row + 1, col    ) ): count+=1\r
+                if (qrCode.isDark(row,     col + 1) ): count+=1\r
+                if (qrCode.isDark(row + 1, col + 1) ): count+=1\r
+                if (count == 0 or count == 4):\r
+                    lostPoint += 3\r
+\r
+        #// LEVEL3\r
+\r
+        for row in range(moduleCount):\r
+            for col in range(moduleCount - 6):\r
+                if (qrCode.isDark(row, col)\r
+                        and not qrCode.isDark(row, col + 1)\r
+                        and  qrCode.isDark(row, col + 2)\r
+                        and  qrCode.isDark(row, col + 3)\r
+                        and  qrCode.isDark(row, col + 4)\r
+                        and not qrCode.isDark(row, col + 5)\r
+                        and  qrCode.isDark(row, col + 6) ):\r
+                    lostPoint += 40\r
+\r
+        for col in range(moduleCount):\r
+            for row in range(moduleCount - 6):\r
+                if (qrCode.isDark(row, col)\r
+                        and not qrCode.isDark(row + 1, col)\r
+                        and  qrCode.isDark(row + 2, col)\r
+                        and  qrCode.isDark(row + 3, col)\r
+                        and  qrCode.isDark(row + 4, col)\r
+                        and not qrCode.isDark(row + 5, col)\r
+                        and  qrCode.isDark(row + 6, col) ):\r
+                    lostPoint += 40\r
+\r
+        #// LEVEL4\r
+\r
+        darkCount = 0;\r
+\r
+        for col in range(moduleCount):\r
+            for row in range(moduleCount):\r
+                if (qrCode.isDark(row, col) ):\r
+                    darkCount+=1\r
+\r
+        ratio = abs(100 * darkCount / moduleCount / moduleCount - 50) / 5\r
+        lostPoint += ratio * 10\r
+\r
+        return lostPoint\r
+\r
+class QRMath:\r
+\r
+    @staticmethod\r
+    def glog(n):\r
+        if (n < 1):\r
+            raise Exception("glog(" + n + ")")\r
+        return LOG_TABLE[n];\r
+    @staticmethod\r
+    def gexp(n):\r
+        while n < 0:\r
+            n += 255\r
+        while n >= 256:\r
+            n -= 255\r
+        return EXP_TABLE[n];\r
+\r
+EXP_TABLE = [x for x in range(256)]\r
+\r
+LOG_TABLE = [x for x in range(256)]\r
+\r
+for i in range(8):\r
+    EXP_TABLE[i] = 1 << i;\r
+\r
+for i in range(8, 256):\r
+    EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]\r
+\r
+for i in range(255):\r
+    LOG_TABLE[EXP_TABLE[i] ] = i\r
+\r
+class QRPolynomial:\r
+\r
+    def __init__(self, num, shift):\r
+\r
+        if (len(num) == 0):\r
+            raise Exception(num.length + "/" + shift)\r
+\r
+        offset = 0\r
+\r
+        while offset < len(num) and num[offset] == 0:\r
+            offset += 1\r
+\r
+        self.num = [0 for x in range(len(num)-offset+shift)]\r
+        for i in range(len(num) - offset):\r
+            self.num[i] = num[i + offset]\r
+\r
+\r
+    def get(self, index):\r
+        return self.num[index]\r
+    def getLength(self):\r
+        return len(self.num)\r
+    def multiply(self, e):\r
+        num = [0 for x in range(self.getLength() + e.getLength() - 1)];\r
+\r
+        for i in range(self.getLength()):\r
+            for j in range(e.getLength()):\r
+                num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) + QRMath.glog(e.get(j) ) )\r
+\r
+        return QRPolynomial(num, 0);\r
+    def mod(self, e):\r
+\r
+        if (self.getLength() - e.getLength() < 0):\r
+            return self;\r
+\r
+        ratio = QRMath.glog(self.get(0) ) - QRMath.glog(e.get(0) )\r
+\r
+        num = [0 for x in range(self.getLength())]\r
+\r
+        for i in range(self.getLength()):\r
+            num[i] = self.get(i);\r
+\r
+        for i in range(e.getLength()):\r
+            num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio)\r
+\r
+        # recursive call\r
+        return QRPolynomial(num, 0).mod(e);\r
+\r
+class QRRSBlock:\r
+\r
+    RS_BLOCK_TABLE = [\r
+\r
+        #// L\r
+        #// M\r
+        #// Q\r
+        #// H\r
+\r
+        #// 1\r
+        [1, 26, 19],\r
+        [1, 26, 16],\r
+        [1, 26, 13],\r
+        [1, 26, 9],\r
+\r
+        #// 2\r
+        [1, 44, 34],\r
+        [1, 44, 28],\r
+        [1, 44, 22],\r
+        [1, 44, 16],\r
+\r
+        #// 3\r
+        [1, 70, 55],\r
+        [1, 70, 44],\r
+        [2, 35, 17],\r
+        [2, 35, 13],\r
+\r
+        #// 4\r
+        [1, 100, 80],\r
+        [2, 50, 32],\r
+        [2, 50, 24],\r
+        [4, 25, 9],\r
+\r
+        #// 5\r
+        [1, 134, 108],\r
+        [2, 67, 43],\r
+        [2, 33, 15, 2, 34, 16],\r
+        [2, 33, 11, 2, 34, 12],\r
+\r
+        #// 6\r
+        [2, 86, 68],\r
+        [4, 43, 27],\r
+        [4, 43, 19],\r
+        [4, 43, 15],\r
+\r
+        #// 7\r
+        [2, 98, 78],\r
+        [4, 49, 31],\r
+        [2, 32, 14, 4, 33, 15],\r
+        [4, 39, 13, 1, 40, 14],\r
+\r
+        #// 8\r
+        [2, 121, 97],\r
+        [2, 60, 38, 2, 61, 39],\r
+        [4, 40, 18, 2, 41, 19],\r
+        [4, 40, 14, 2, 41, 15],\r
+\r
+        #// 9\r
+        [2, 146, 116],\r
+        [3, 58, 36, 2, 59, 37],\r
+        [4, 36, 16, 4, 37, 17],\r
+        [4, 36, 12, 4, 37, 13],\r
+\r
+        #// 10\r
+        [2, 86, 68, 2, 87, 69],\r
+        [4, 69, 43, 1, 70, 44],\r
+        [6, 43, 19, 2, 44, 20],\r
+        [6, 43, 15, 2, 44, 16],\r
+\r
+      # 11\r
+      [4, 101, 81],\r
+      [1, 80, 50, 4, 81, 51],\r
+      [4, 50, 22, 4, 51, 23],\r
+      [3, 36, 12, 8, 37, 13],\r
+\r
+      # 12\r
+      [2, 116, 92, 2, 117, 93],\r
+      [6, 58, 36, 2, 59, 37],\r
+      [4, 46, 20, 6, 47, 21],\r
+      [7, 42, 14, 4, 43, 15],\r
+\r
+      # 13\r
+      [4, 133, 107],\r
+      [8, 59, 37, 1, 60, 38],\r
+      [8, 44, 20, 4, 45, 21],\r
+      [12, 33, 11, 4, 34, 12],\r
+\r
+      # 14\r
+      [3, 145, 115, 1, 146, 116],\r
+      [4, 64, 40, 5, 65, 41],\r
+      [11, 36, 16, 5, 37, 17],\r
+      [11, 36, 12, 5, 37, 13],\r
+\r
+      # 15\r
+      [5, 109, 87, 1, 110, 88],\r
+      [5, 65, 41, 5, 66, 42],\r
+      [5, 54, 24, 7, 55, 25],\r
+      [11, 36, 12],\r
+\r
+      # 16\r
+      [5, 122, 98, 1, 123, 99],\r
+      [7, 73, 45, 3, 74, 46],\r
+      [15, 43, 19, 2, 44, 20],\r
+      [3, 45, 15, 13, 46, 16],\r
+\r
+      # 17\r
+      [1, 135, 107, 5, 136, 108],\r
+      [10, 74, 46, 1, 75, 47],\r
+      [1, 50, 22, 15, 51, 23],\r
+      [2, 42, 14, 17, 43, 15],\r
+\r
+      # 18\r
+      [5, 150, 120, 1, 151, 121],\r
+      [9, 69, 43, 4, 70, 44],\r
+      [17, 50, 22, 1, 51, 23],\r
+      [2, 42, 14, 19, 43, 15],\r
+\r
+      # 19\r
+      [3, 141, 113, 4, 142, 114],\r
+      [3, 70, 44, 11, 71, 45],\r
+      [17, 47, 21, 4, 48, 22],\r
+      [9, 39, 13, 16, 40, 14],\r
+\r
+      # 20\r
+      [3, 135, 107, 5, 136, 108],\r
+      [3, 67, 41, 13, 68, 42],\r
+      [15, 54, 24, 5, 55, 25],\r
+      [15, 43, 15, 10, 44, 16],\r
+\r
+      # 21\r
+      [4, 144, 116, 4, 145, 117],\r
+      [17, 68, 42],\r
+      [17, 50, 22, 6, 51, 23],\r
+      [19, 46, 16, 6, 47, 17],\r
+\r
+      # 22\r
+      [2, 139, 111, 7, 140, 112],\r
+      [17, 74, 46],\r
+      [7, 54, 24, 16, 55, 25],\r
+      [34, 37, 13],\r
+\r
+      # 23\r
+      [4, 151, 121, 5, 152, 122],\r
+      [4, 75, 47, 14, 76, 48],\r
+      [11, 54, 24, 14, 55, 25],\r
+      [16, 45, 15, 14, 46, 16],\r
+\r
+      # 24\r
+      [6, 147, 117, 4, 148, 118],\r
+      [6, 73, 45, 14, 74, 46],\r
+      [11, 54, 24, 16, 55, 25],\r
+      [30, 46, 16, 2, 47, 17],\r
+\r
+      # 25\r
+      [8, 132, 106, 4, 133, 107],\r
+      [8, 75, 47, 13, 76, 48],\r
+      [7, 54, 24, 22, 55, 25],\r
+      [22, 45, 15, 13, 46, 16],\r
+\r
+      # 26\r
+      [10, 142, 114, 2, 143, 115],\r
+      [19, 74, 46, 4, 75, 47],\r
+      [28, 50, 22, 6, 51, 23],\r
+      [33, 46, 16, 4, 47, 17],\r
+\r
+      # 27\r
+      [8, 152, 122, 4, 153, 123],\r
+      [22, 73, 45, 3, 74, 46],\r
+      [8, 53, 23, 26, 54, 24],\r
+      [12, 45, 15, 28, 46, 16],\r
+\r
+      # 28\r
+      [3, 147, 117, 10, 148, 118],\r
+      [3, 73, 45, 23, 74, 46],\r
+      [4, 54, 24, 31, 55, 25],\r
+      [11, 45, 15, 31, 46, 16],\r
+\r
+      # 29\r
+      [7, 146, 116, 7, 147, 117],\r
+      [21, 73, 45, 7, 74, 46],\r
+      [1, 53, 23, 37, 54, 24],\r
+      [19, 45, 15, 26, 46, 16],\r
+\r
+      # 30\r
+      [5, 145, 115, 10, 146, 116],\r
+      [19, 75, 47, 10, 76, 48],\r
+      [15, 54, 24, 25, 55, 25],\r
+      [23, 45, 15, 25, 46, 16],\r
+\r
+      # 31\r
+      [13, 145, 115, 3, 146, 116],\r
+      [2, 74, 46, 29, 75, 47],\r
+      [42, 54, 24, 1, 55, 25],\r
+      [23, 45, 15, 28, 46, 16],\r
+\r
+      # 32\r
+      [17, 145, 115],\r
+      [10, 74, 46, 23, 75, 47],\r
+      [10, 54, 24, 35, 55, 25],\r
+      [19, 45, 15, 35, 46, 16],\r
+\r
+      # 33\r
+      [17, 145, 115, 1, 146, 116],\r
+      [14, 74, 46, 21, 75, 47],\r
+      [29, 54, 24, 19, 55, 25],\r
+      [11, 45, 15, 46, 46, 16],\r
+\r
+      # 34\r
+      [13, 145, 115, 6, 146, 116],\r
+      [14, 74, 46, 23, 75, 47],\r
+      [44, 54, 24, 7, 55, 25],\r
+      [59, 46, 16, 1, 47, 17],\r
+\r
+      # 35\r
+      [12, 151, 121, 7, 152, 122],\r
+      [12, 75, 47, 26, 76, 48],\r
+      [39, 54, 24, 14, 55, 25],\r
+      [22, 45, 15, 41, 46, 16],\r
+\r
+      # 36\r
+      [6, 151, 121, 14, 152, 122],\r
+      [6, 75, 47, 34, 76, 48],\r
+      [46, 54, 24, 10, 55, 25],\r
+      [2, 45, 15, 64, 46, 16],\r
+\r
+      # 37\r
+      [17, 152, 122, 4, 153, 123],\r
+      [29, 74, 46, 14, 75, 47],\r
+      [49, 54, 24, 10, 55, 25],\r
+      [24, 45, 15, 46, 46, 16],\r
+\r
+      # 38\r
+      [4, 152, 122, 18, 153, 123],\r
+      [13, 74, 46, 32, 75, 47],\r
+      [48, 54, 24, 14, 55, 25],\r
+      [42, 45, 15, 32, 46, 16],\r
+\r
+      # 39\r
+      [20, 147, 117, 4, 148, 118],\r
+      [40, 75, 47, 7, 76, 48],\r
+      [43, 54, 24, 22, 55, 25],\r
+      [10, 45, 15, 67, 46, 16],\r
+\r
+      # 40\r
+      [19, 148, 118, 6, 149, 119],\r
+      [18, 75, 47, 31, 76, 48],\r
+      [34, 54, 24, 34, 55, 25],\r
+      [20, 45, 15, 61, 46, 16]\r
+\r
+    ]\r
+\r
+    def __init__(self, totalCount, dataCount):\r
+        self.totalCount = totalCount\r
+        self.dataCount = dataCount\r
+\r
+    @staticmethod\r
+    def getRSBlocks(typeNumber, errorCorrectLevel):\r
+        rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);\r
+        if rsBlock == None:\r
+            raise Exception("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel)\r
+\r
+        length = len(rsBlock) / 3\r
+\r
+        list = []\r
+\r
+        for i in range(length):\r
+\r
+            count = rsBlock[i * 3 + 0]\r
+            totalCount = rsBlock[i * 3 + 1]\r
+            dataCount  = rsBlock[i * 3 + 2]\r
+\r
+            for j in range(count):\r
+                list.append(QRRSBlock(totalCount, dataCount))\r
+\r
+        return list;\r
+\r
+    @staticmethod\r
+    def getRsBlockTable(typeNumber, errorCorrectLevel):\r
+        if errorCorrectLevel == QRErrorCorrectLevel.L:\r
+            return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];\r
+        elif errorCorrectLevel == QRErrorCorrectLevel.M:\r
+            return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];\r
+        elif errorCorrectLevel ==  QRErrorCorrectLevel.Q:\r
+            return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];\r
+        elif errorCorrectLevel ==  QRErrorCorrectLevel.H:\r
+            return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];\r
+        else:\r
+            return None;\r
+\r
+class QRBitBuffer:\r
+    def __init__(self):\r
+        self.buffer = []\r
+        self.length = 0\r
+    def __repr__(self):\r
+        return ".".join([str(n) for n in self.buffer])\r
+    def get(self, index):\r
+        bufIndex = math.floor(index / 8)\r
+        val = ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1\r
+        print "get ", val\r
+        return ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1\r
+    def put(self, num, length):\r
+        for i in range(length):\r
+            self.putBit( ( (num >> (length - i - 1) ) & 1) == 1)\r
+    def getLengthInBits(self):\r
+        return self.length\r
+    def putBit(self, bit):\r
+        bufIndex = self.length // 8\r
+        if len(self.buffer) <= bufIndex:\r
+            self.buffer.append(0)\r
+        if bit:\r
+            self.buffer[bufIndex] |= (0x80 >> (self.length % 8) )\r
+        self.length+=1\r
+\r
+class QRCodeInkscape(inkex.Effect):\r
+    def __init__(self):\r
+        inkex.Effect.__init__(self)\r
+        \r
+        #PARSE OPTIONS\r
+        self.OptionParser.add_option("--text",\r
+            action="store", type="string",\r
+            dest="TEXT", default='www.inkscape.org')\r
+        self.OptionParser.add_option("--typenumber",\r
+            action="store", type="string",\r
+            dest="TYPENUMBER", default="0")\r
+        self.OptionParser.add_option("--correctionlevel",\r
+            action="store", type="string",\r
+            dest="CORRECTIONLEVEL", default="0")\r
+        self.OptionParser.add_option("--modulesize",\r
+            action="store", type="float",\r
+            dest="MODULESIZE", default=10)\r
+            \r
+    def effect(self):\r
+        \r
+        so = self.options\r
+        \r
+        if so.TEXT == '':  #abort if converting blank text\r
+            inkex.errormsg(_('Please enter an input text'))\r
+        else:\r
+        \r
+            #INKSCAPE GROUP TO CONTAIN EVERYTHING\r
+            \r
+            centre = self.view_center   #Put in in the centre of the current view\r
+            grp_transform = 'translate' + str( centre )\r
+            grp_name = 'QRCode'\r
+            grp_attribs = {inkex.addNS('label','inkscape'):grp_name,\r
+                           'transform':grp_transform }\r
+            grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs) #the group to put everything in\r
+            \r
+            #GENERATE THE QRCODE\r
+            qr = QRCode(int(so.TYPENUMBER), int(so.CORRECTIONLEVEL))\r
+            qr.addData(so.TEXT)\r
+            qr.make()\r
+            qr.makeSVG(grp, so.MODULESIZE)\r
+            \r
+if __name__ == '__main__':\r
+    e = QRCodeInkscape()\r
+    e.affect()\r
+\r
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99\r