Full Code of 7sDream/pyqart for AI

master c40c693cdedb cached
52 files
111.5 KB
33.2k tokens
264 symbols
1 requests
Download .txt
Repository: 7sDream/pyqart
Branch: master
Commit: c40c693cdedb
Files: 52
Total size: 111.5 KB

Directory structure:
gitextract_kd70hrty/

├── .gitignore
├── LICENSE
├── README.md
├── README.zh.md
├── pyqart/
│   ├── __init__.py
│   ├── art/
│   │   ├── __init__.py
│   │   ├── bitblock.py
│   │   ├── exception.py
│   │   ├── qart.py
│   │   ├── source.py
│   │   └── target.py
│   ├── common/
│   │   ├── __init__.py
│   │   ├── bit_funcs.py
│   │   ├── bits.py
│   │   └── exception.py
│   ├── qart_entry.py
│   ├── qr/
│   │   ├── __init__.py
│   │   ├── args/
│   │   │   ├── __init__.py
│   │   │   ├── args.py
│   │   │   ├── mask.py
│   │   │   ├── rotation.py
│   │   │   └── version.py
│   │   ├── data/
│   │   │   ├── __init__.py
│   │   │   ├── alphanumeric.py
│   │   │   ├── base.py
│   │   │   ├── data.py
│   │   │   ├── exception.py
│   │   │   ├── numbers.py
│   │   │   └── raw.py
│   │   ├── ec/
│   │   │   ├── __init__.py
│   │   │   ├── gf.py
│   │   │   ├── poly.py
│   │   │   └── rsencoder.py
│   │   ├── exception.py
│   │   ├── painter/
│   │   │   ├── __init__.py
│   │   │   ├── canvas.py
│   │   │   ├── exception.py
│   │   │   ├── painter.py
│   │   │   └── point.py
│   │   └── printer/
│   │       ├── __init__.py
│   │       ├── base.py
│   │       ├── halftone_printer.py
│   │       ├── image_printer.py
│   │       └── string_printer.py
│   └── qr_entry.py
├── setup.py
└── test/
    ├── __init__.py
    ├── test_alphanumeric.py
    ├── test_bits.py
    ├── test_bits_utils.py
    ├── test_encode_numbers.py
    └── test_encode_raw.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Pycharm files
.idea/

# personal test file
test.py
example.jpg

# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject



================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 7sDream

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# PyQArt - QArt Python implementation

[中文版 README](https://github.com/7sDream/pyqart/blob/master/README.zh.md)

## introduction

QArt is a method of combining QrCode of an URL with any image, which was submitted in [an article][qart-article] writen by [Russ Cox][russ-cos-google-plus] on his personal website.

An Example(come from the article):

![QArt Example][qart-example]

This repo is Python implementation of it.

## Install

```
pip install pyqart
```

**Note: Support Python3 only, please make sure you are using pip of Python3.**

## Usage

For code reuse, I split the lib to two part. One for generate normal QrCode, another for generate QArt.

### The Qr Part

Use `pyqr` CLI to create normal QrCode.

```
 pyqr -p 5 -c 102 204 255 "Hello World!" -o qr.png
 ```
 
 The options:
 
 - `-p` for point size of QrQCode, by pixel, default is 3 pixel.
 - `-c` for color of point, default is black. Background color can be set with `-g` option, default is white.

![qr code: hello world][my-qr-img]

If you want show it in terminal, just don't provide `-o` option:

```bash
pyqr "Hello World"
```

Then you will see:

![qr in terminal: hello world][my-qr-terminal]

The actual result you will see depends on your font setting, I'm using Dejavu Sans Mono.

Yes, it is only useful for small QrCode. 

Run `pyqr -h` for more options and their effect.

### The Art Part

Use `pyqart` CLI to create QArt. It may take a long time, please be patient :)

This is an example that mix my blog url and my Github avatar: 

```
pyqart -v 8 -c 102 204 255 "http://0v0.link/" photo.jpg -o qart.png
```

My Github avatar:

![][my-github-avatar]

The QArt Code:

![][my-qart-img]

Not meet your expectations? Try `-n` option to pick point at random(default is pick low-contrast region pixels first):

```bash
pyqart -n -c 102 204 255 -v 8 "http://0v0.link/" photo.jpg -o qart-n.png
```

![][my-qart-n-img]

Still not satisfied? Use `-y` option to enhance the accuracy of the central region by giving up the control of the edge pixels:

![][my-qart-y-img]

`-y` and `-n` can be used at the same time, but no obvious improvement.

**Note: because that `-y` option will only use data block, ignore error correction block,it reduce many many many calculate. It has about 30x to 100x speed up compare with no `-y` option case. So I strongly recommend using `-y` option whenever you needn't make a full picture fitting.**

Use `-r` option to set rotation degree, The controllable data region can be changed into a horizontal area, it will make it easier to process very wide picture.

![][my-pyqart-y-r-img]

Run `pyqart -h` for more options and their effect.

### Use it in your codes as a module

Documentation is in preparation.

## Gallery

![][python-qr]

python.org(used -d option, means dithering, see help message for more info.)

![][github-qr]

github.com

![][bilibili-qr]

bilibili.com (An ACG videos website)

## Halftone and HalfArt support

Halftone support added in version 0.1.0, and I made another new method which combined Halftone and QArt, so I call it HalfArt temporarily.

## Arguments for all methods

The following code shows arguments to get output image of all kind of method:

```python
from pyqart import QArtist, QrHalftonePrinter, QrImagePrinter, QrPainter

QR_VERSION = 10
POINT_PIXEL = 3

artist = QArtist('http://www.nankai.edu.cn/', 'example.jpg', QR_VERSION)
painter = QrPainter('http://www.nankai.edu.cn/', QR_VERSION)
artist_data_only = QArtist('http://www.nankai.edu.cn/', 'example.jpg',
                           QR_VERSION, only_data=True)

# normal
QrImagePrinter.print(painter, path='normal.png', point_width=POINT_PIXEL)
# Halftone
QrHalftonePrinter.print(painter, path='halftone.png', img='example.jpg',
                        point_width=POINT_PIXEL, colorful=False)
# Halftone colorful
QrHalftonePrinter.print(painter, path='halftone-color.png', img='example.jpg',
                        point_width=POINT_PIXEL)
# Halftone pixel
QrHalftonePrinter.print(painter, path='halftone-pixel.png', img='example.jpg',
                        point_width=POINT_PIXEL, colorful=False,
                        pixelization=True)
# QArt
QrImagePrinter.print(artist, path='qart.png', point_width=POINT_PIXEL)
# QArt data only
QrImagePrinter.print(artist_data_only, path='qart-data-only.png',
                     point_width=POINT_PIXEL)
# HalfArt
QrHalftonePrinter.print(artist, path='halfart.png', point_width=POINT_PIXEL)
# HalfArt data only
QrHalftonePrinter.print(artist_data_only, path='halfart-data-only.png',
                        point_width=POINT_PIXEL)
```

### Result example for all method

|  |  |  |
| :-: | :-: | :-: |
| ![][halftone.png]| ![][halftone-color.png] | ![][halftone-pixel.png] |
| Halftone | Halftone colorful | Halftone pixel |
| ![][qart.png] | ![][qart-data-only.png] | |
| QArt | QArt data only | |
| ![][halfart.png] | ![][halfart-data-only.png] | |
| HalfArt | HalfArt data only | |

## TODO

- [x] Make QrPainter decided argument by itself.
- [x] Art part
- [x] CLI
- [x] Package
- [x] Halftone support
- [x] self-made HalfArt method
- [ ] GUI
- [ ] Use Cython to accelerate Reed-Solomon error correction
- [ ] Docs
- [ ] Tests

## Other Implementation

- Golang: [qr][qr] by [Russ Cox][russ-cos-google-plus]
- Java: [qart4j][qart4j] by [dieforfree][dieforfree]

## Acknowledgements

- All credit goes to [Russ Cos][russ-cos-google-plus], Thanks for his article and implement.
- Thanks for [qart4j project][qart4j] by [dieforfree][dieforfree],which helps me so much on how to implement the art part.
- Thanks to a series of articles named [QR Code Tutorial][tutorial] in thonky.com, It's very detailed. Whenever I faced problem about encoding or error correction, I will go to it for help.
- Thanks to the Python programing language。

## LICENSE

MIT.

See LICENSE.

[russ-cos-google-plus]: https://plus.google.com/+RussCox-rsc
[qart-article]: http://research.swtch.com/qart
[qart-example]: http://ww4.sinaimg.cn/large/88e401f0gw1f6dl845naoj205g05ga9y.jpg
[my-qr-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6ir3ifivzj20370370ss.jpg
[my-qr-terminal]: http://ww2.sinaimg.cn/large/88e401f0gw1f6ir4taf7hj209008c3ze.jpg
[my-github-avatar]: http://ww3.sinaimg.cn/large/88e401f0gw1f6iyj9nuwhj2049049q2v.jpg
[my-qart-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6ir8t0mbej20490490t2.jpg
[my-qart-n-img]: http://ww1.sinaimg.cn/large/88e401f0gw1f6irh15ouuj2049049mxp.jpg
[my-qart-y-img]: http://ww2.sinaimg.cn/large/88e401f0gw1f6irbnfjozj20490490t4.jpg
[my-pyqart-y-r-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6jd7w10r7j205l05lt91.jpg
[qr]: https://code.google.com/p/rsc/source/browse/qr
[dieforfree]: https://github.com/dieforfree
[qart4j]: https://github.com/dieforfree/qart4j
[tutorial]: http://www.thonky.com/qr-code-tutorial/

[python-qr]: http://ww1.sinaimg.cn/large/88e401f0gw1f6iz81tkwpj204x04xaaf.jpg
[github-qr]: http://ww4.sinaimg.cn/large/88e401f0gw1f6izdtv2kqj204x04x0sy.jpg
[bilibili-qr]: http://ww3.sinaimg.cn/large/88e401f0gw1f6j0ds93k9j204x04x74m.jpg

[halftone.png]: http://rikka-10066868.image.myqcloud.com/f62cbc2f-1e38-4a94-80aa-0be1a0c32b55.png
[halftone-color.png]: http://rikka-10066868.image.myqcloud.com/d96d057a-42d2-469b-9b65-0eabd2bd915f.png
[halftone-pixel.png]: http://rikka-10066868.image.myqcloud.com/00da6fa8-5035-4ba6-8c33-584b54e73e2d.png
[qart.png]: http://rikka-10066868.image.myqcloud.com/d2f3febb-a535-4154-8ebc-80183701c47d.png
[qart-data-only.png]: http://rikka-10066868.image.myqcloud.com/59834cea-5d44-41c3-b759-780c56c9789b.png
[halfart.png]: http://rikka-10066868.image.myqcloud.com/8b0847b9-c3fc-451d-b554-7bdc3a53f7e9.png
[halfart-data-only.png]: http://rikka-10066868.image.myqcloud.com/9f4fd92e-99ff-4aca-a252-b6c1ab709e65.png


================================================
FILE: README.zh.md
================================================
# PyQArt - QArt 的  Python 实现

[Readme in English](https://github.com/7sDream/pyqart/blob/master/README.md)

## 简介

QArt 是由 [Russ Cox][russ-cos-google-plus] 在他个人网站的[一篇文章][qart-article]中提出的一种将包含 URL 的二维码与图像结合的方法。

示例图片(来源于 Russ Cox 的文章):

![QArt Example][qart-example]

这个库是 QArt 的 Python 实现版本。

## 安装

```bash
pip install pyqart
```

**注:只支持 Python3,请确认你使用的是 python3 版本的 pip。**

## 使用

为便于重用,我将库分成了两部分,一部分是普通二维码生成,另一部分则将 URL 二维码与图像结合。

### Qr 部分

使用 `pyqr` 命令行程序,可以创建普通二维码。

```
 pyqr -p 5 -c 102 204 255 "Hello World!" -o qr.png
```

其中:

- `-p` 参数指定生成的二维码图片中,每个填充点的大小,默认是 3 像素。
- `-c` 参数指定填充点的颜色,默认是黑色。背景色默认为白色,可以用 `-g` 参数设定。

![qr code: hello world][my-qr-img]

如果你想在终端里查看的话,不提供 `-o` 参数即可:

```bash
pyqr "Hello World"
```

输出如下:

![qr in terminal: hello world][my-qr-terminal]

显示效果和你终端的字体有关,我的字体是 Dejavu Sans Mono.

当然,终端只能用于显示比较小的二维码。

有关二维码生成的更多参数和它们的作用请使用 `pyqr -h` 命令查看。

### Art 部分

使用 `pyqart` 命令行程序创建艺术二维码。(所需时间可能较长,请耐心等待)

使用我的博客网址和 Github 头像来做例子,`-v` 参数指定二维码的大小。

```
pyqart -v 8 -c 102 204 255 "http://0v0.link/" photo.jpg -o qart.png
```

这是我的 Github 头像:

![][my-github-avatar]

生成的二维码如下,扫描一下就会跳转到我的博客啦:

![][my-qart-img]

可能效果不太好,试试使用 `-n` 参数来随机选取像素点(默认情况下会先处理大片相同颜色的区域):

```bash
pyqart -n -c 102 204 255 -v 8 "http://0v0.link/" photo.jpg -o qart-n.png
```

![][my-qart-n-img]

可能还是不太好?再试试 `-y` 参数,它通过放弃边缘区域来加强中间区域的逼近效果:

```bash
pyqart -y -c 102 204 255 -v 8 "http://0v0.link/" photo.jpg -o qart-y.png
```

![][my-qart-y-img]

`-y` 和 `-n` 参数也可以结合起来使用,不过提升不会很明显。

**注意: `-y` 参数由于只只使用数据块而不使用纠错块,减少了很多很多很多操作,相比没有 `-y` 参数大概有 30 到 100 倍的速度提升,强烈建议在不需要全图拟合时使用 `-y` 参数。**

另外,使用 `-r` 参数指定二维码的旋转角度,可以把可控制的数据区变为横向,方便扁长图形处理:

![][my-pyqart-y-r-img]

有关 QArt 生成的更多参数和它们的作用请使用 `pyqart -h` 命令查看。

### 作为模块使用

文档正在编写中。

## 更多示例

![][python-qr]

Python 官网。(此示例使用了 -d 参数,请查看帮助获取更多信息)

![][github-qr]

Github 首页。

![][bilibili-qr]

哔哩哔哩。

## Halftone 和 HalfArt 支持

0.1.0 版本增加了 Halftone 支持,另外也实现了一种结合了 QArt 和 Halftone 的新算法,我暂时命名为 HalfArt。

## 各方法所用参数

以下代码展示了输出各种格式的所需参数:

```python
from pyqart import QArtist, QrHalftonePrinter, QrImagePrinter, QrPainter

QR_VERSION = 10
POINT_PIXEL = 3

artist = QArtist('http://www.nankai.edu.cn/', 'example.jpg', QR_VERSION)
painter = QrPainter('http://www.nankai.edu.cn/', QR_VERSION)
artist_data_only = QArtist('http://www.nankai.edu.cn/', 'example.jpg',
                           QR_VERSION, only_data=True)

# normal
QrImagePrinter.print(painter, path='normal.png', point_width=POINT_PIXEL)
# Halftone
QrHalftonePrinter.print(painter, path='halftone.png', img='example.jpg',
                        point_width=POINT_PIXEL, colorful=False)
# Halftone colorful
QrHalftonePrinter.print(painter, path='halftone-color.png', img='example.jpg',
                        point_width=POINT_PIXEL)
# Halftone pixel
QrHalftonePrinter.print(painter, path='halftone-pixel.png', img='example.jpg',
                        point_width=POINT_PIXEL, colorful=False,
                        pixelization=True)
# QArt
QrImagePrinter.print(artist, path='qart.png', point_width=POINT_PIXEL)
# QArt data only
QrImagePrinter.print(artist_data_only, path='qart-data-only.png',
                     point_width=POINT_PIXEL)
# HalfArt
QrHalftonePrinter.print(artist, path='halfart.png', point_width=POINT_PIXEL)
# HalfArt data only
QrHalftonePrinter.print(artist_data_only, path='halfart-data-only.png',
                        point_width=POINT_PIXEL)
```

### 各方法结果样例

|  |  |  |
| :-: | :-: | :-: |
| ![][halftone.png]| ![][halftone-color.png] | ![][halftone-pixel.png] |
| Halftone | Halftone colorful | Halftone pixel |
| ![][qart.png] | ![][qart-data-only.png] | |
| QArt | QArt data only | |
| ![][halfart.png] | ![][halfart-data-only.png] | |
| HalfArt | HalfArt data only | |

## TODO

- [x] 让 QrPainter 能自己决定参数
- [x] Art 部分
- [x] CLI
- [x] 打包
- [x] Halftone 支持
- [x] 自制 HalfArt 方法
- [ ] GUI
- [ ] 使用 Cython 加快里德所罗门码编码速度
- [ ] 文档
- [ ] 测试

## 其他实现版本

- Golang: [qr][qr] by [Russ Cox][russ-cos-google-plus]
- Java: [qart4j][qart4j] by [dieforfree][dieforfree]

## 致谢

- 所有一切都源自 [Russ Cos][russ-cos-google-plus] 的文章,感谢他。
- 感谢 [dieforfree][dieforfree] 的 [qart4j 项目][qart4j],它给我提供了很多如何实现 art 部分参考。
- 感谢 thonky.com 的 [二维码原理指导][tutorial] 系列文章,非常详细,关于编码和纠错中不懂的地方多亏了它。
- 感谢 Python。

## 协议

MIT。

参见 LICENSE 文件。

[russ-cos-google-plus]: https://plus.google.com/+RussCox-rsc
[qart-article]: http://research.swtch.com/qart
[qart-example]: http://ww4.sinaimg.cn/large/88e401f0gw1f6dl845naoj205g05ga9y.jpg
[my-qr-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6ir3ifivzj20370370ss.jpg
[my-qr-terminal]: http://ww2.sinaimg.cn/large/88e401f0gw1f6ir4taf7hj209008c3ze.jpg
[my-github-avatar]: http://ww3.sinaimg.cn/large/88e401f0gw1f6iyj9nuwhj2049049q2v.jpg
[my-qart-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6ir8t0mbej20490490t2.jpg
[my-qart-n-img]: http://ww1.sinaimg.cn/large/88e401f0gw1f6irh15ouuj2049049mxp.jpg
[my-qart-y-img]: http://ww2.sinaimg.cn/large/88e401f0gw1f6irbnfjozj20490490t4.jpg
[my-pyqart-y-r-img]: http://ww3.sinaimg.cn/large/88e401f0gw1f6jd7w10r7j205l05lt91.jpg
[qr]: https://code.google.com/p/rsc/source/browse/qr
[dieforfree]: https://github.com/dieforfree
[qart4j]: https://github.com/dieforfree/qart4j
[tutorial]: http://www.thonky.com/qr-code-tutorial/

[python-qr]: http://ww1.sinaimg.cn/large/88e401f0gw1f6iz81tkwpj204x04xaaf.jpg
[github-qr]: http://ww4.sinaimg.cn/large/88e401f0gw1f6izdtv2kqj204x04x0sy.jpg
[bilibili-qr]: http://ww3.sinaimg.cn/large/88e401f0gw1f6j0ds93k9j204x04x74m.jpg

[halftone.png]: http://rikka-10066868.image.myqcloud.com/f62cbc2f-1e38-4a94-80aa-0be1a0c32b55.png
[halftone-color.png]: http://rikka-10066868.image.myqcloud.com/d96d057a-42d2-469b-9b65-0eabd2bd915f.png
[halftone-pixel.png]: http://rikka-10066868.image.myqcloud.com/00da6fa8-5035-4ba6-8c33-584b54e73e2d.png
[qart.png]: http://rikka-10066868.image.myqcloud.com/d2f3febb-a535-4154-8ebc-80183701c47d.png
[qart-data-only.png]: http://rikka-10066868.image.myqcloud.com/59834cea-5d44-41c3-b759-780c56c9789b.png
[halfart.png]: http://rikka-10066868.image.myqcloud.com/8b0847b9-c3fc-451d-b554-7bdc3a53f7e9.png
[halfart-data-only.png]: http://rikka-10066868.image.myqcloud.com/9f4fd92e-99ff-4aca-a252-b6c1ab709e65.png


================================================
FILE: pyqart/__init__.py
================================================
from .qr import (
    QrData,
    QrPainter,
    # ------------
    QrBasePrinter,
    QrImagePrinter,
    QrStringPrinter,
    QrHalftonePrinter,
    # ------------
    QrException,
)

from .art import QArtist

__version__ = '0.1.0'


================================================
FILE: pyqart/art/__init__.py
================================================
from .qart import QArtist


================================================
FILE: pyqart/art/bitblock.py
================================================
# Added at : 2016.8.3
# Author   : 7sDream
# Usage    : A block of bits. In this class, we let each point (including EC)
#               as much as possible to meet the color of image in it's position.

from ..common import Bits, one_at, bit_at, BIT_PER_CW
from ..qr.ec import RSEncoder

__all__ = ['BitBlock']

_VS_CACHE = {}


def _copy(i):
    vs = []
    for line in _VS_CACHE[i]:
        vs.append([x for x in line])
    return vs


def _create_vs(dbc, ecbc):
    if dbc not in _VS_CACHE:
        print('can\'t find in cache, calculating...', end='', flush=True)
        vs = []
        for i in range(dbc):
            b = [0] * (i // 8) + [one_at(i % 8)] + [0] * (dbc // 8 - i // 8 - 1)
            b += RSEncoder.encode(b, ecbc // BIT_PER_CW, False)
            vs.append(b)
        print('Done')
        _VS_CACHE[dbc] = vs
    else:
        print('found in cache.')
    return _copy(dbc)


class BitBlock(object):
    def __init__(self, bits, di, dbc, eci, ecbc):
        self._dbc = dbc
        self._bits = Bits.copy_from(bits, di, dbc)
        self._bits.extend(bits, eci, ecbc)
        self._bits = self._bits.as_int_list

        # vector space
        self._vs = _create_vs(dbc, ecbc)

        self._locked_index = len(self._vs)
        self._already_set = set()
        self._max_index = len(self._bits) * 8

    def set(self, index, value):
        assert isinstance(index, int)
        assert isinstance(value, bool)
        assert 0 <= index < self._max_index

        if index in self._already_set:
            return False
        if len(self._already_set) >= self._dbc:
            return False

        found = False

        for i in range(self._locked_index):
            if bit_at(self._vs[i][index // 8], 8, index % 8) is False:
                continue
            if not found:
                found = True
                if i != 0:
                    self._exchange_row(0, i)
                continue
            self._vs_xor_line(i, 0)

        if not found:
            return False

        for i in range(self._locked_index, len(self._vs)):
            if bit_at(self._vs[i][index // 8], 8, index % 8) is True:
                self._vs_xor_line(i, 0)

        if bit_at(self._bits[index // 8], 8, index % 8) is not value:
            self._bits_xor_with_vs(0)

        self._exchange_row(0, self._locked_index - 1)
        self._locked_index -= 1
        self._already_set.add(index)

        return True

    def bits(self):
        return Bits.copy_from(bytearray(self._bits))

    def _vs_xor_line(self, i, j):
        self._vs[i] = [a ^ b for a, b in zip(self._vs[i], self._vs[j])]

    def _bits_xor_with_vs(self, i):
        self._bits = [a ^ b for a, b in zip(self._bits, self._vs[i])]

    def _exchange_row(self, i, j):
        self._vs[i], self._vs[j] = self._vs[j], self._vs[i]


================================================
FILE: pyqart/art/exception.py
================================================
# Added at : 2016.8.2
# Author   : 7sDream
# Usage    : Exceptions happened at art part.

from ..qr import QrException

__all__ = ['ArtException']


class ArtException(QrException):
    pass


================================================
FILE: pyqart/art/qart.py
================================================
# Added at : 2016.8.2
# Author   : 7sDream
# Usage    : Accept data and source image, make a QArt.

import itertools
from random import randint

from .source import QArtSourceImage
from .bitblock import BitBlock
from ..qr import QrData, QrPainter
from ..qr.data.numbers import Numbers
from ..qr.painter.point import QrPointType
from ..qr.ec import RSEncoder
from ..common import Bits, BIT_PER_CW

__all__ = ['QArtist']

INF = float('inf')


class QArtist(QrPainter):
    def __init__(self, url, img, version=None, mask=None, level=0, rotation=0,
                 dither=False, only_data=False, rand=False, higher_first=False,
                 dy=None, dx=None):
        assert isinstance(img, (str, QArtSourceImage))
        if isinstance(img, str):
            img = QArtSourceImage(img)
        self.source = img
        self.dy = dy
        self.dx = dx
        self._only_data = bool(only_data)
        self._higher_first = bool(higher_first)
        data = QrData(url + '#', level)
        super().__init__(data, version, mask, rotation)
        args, _, _ = self.get_params()
        print('Processing input image...', end='', flush=True)
        self._targets = self.source.to_targets(
            self.canvas, args, bool(dither), rand, dy, dx)
        self.dither = dither
        print('Done.')
        self._bits = None

    @property
    def bits(self):
        if self._bits is not None:
            return self._bits
        args, available, used = self.get_params()
        cci_length = args.cci_length_of(Numbers)
        available_for_number = available - 4 - cci_length
        used += 4 + cci_length
        if available_for_number < 4:
            return super().bits
        else:
            numbers_count = available_for_number // 10 * 3
            remaining = available_for_number % 10
            if remaining >= 7:
                numbers_count += 2
                remaining -= 7
            elif remaining >= 4:
                numbers_count += 1
                remaining -= 4
            upper = args.dcwc * BIT_PER_CW - remaining

        self._data.put_numbers('0' * numbers_count)

        while True:
            bits = super().bits
            di = 0
            eci = args.dcwc * BIT_PER_CW
            ecbc = args.eccwcpb * BIT_PER_CW
            data_bits = Bits()
            ec_bits = Bits()

            for i in range(args.bc):
                dbc = args.dcwcof(i) * BIT_PER_CW
                low = 0
                high = dbc
                if di < used:
                    low = used - di
                    if low >= dbc:
                        data_bits.extend(bits, di, dbc)
                        ec_bits.extend(bits, eci, ecbc)
                        di += dbc
                        eci += ecbc
                        continue

                if di + dbc > upper:
                    high = upper - di
                    if high <= 0:
                        data_bits.extend(bits, di, dbc)
                        ec_bits.extend(bits, eci, ecbc)
                        di += dbc
                        eci += ecbc
                        continue

                if not self._only_data:
                    print('Create BitBlock', '{i}/{bc}...'.format(
                        i=i+1, bc=args.bc,
                    ), end='', flush=True)
                    block = BitBlock(bits, di, dbc, eci, ecbc)
                else:
                    block = Bits.copy_from(bits, di, dbc)

                # Lock uncontrollable bits

                locked_bits = set()

                if not self._only_data:
                    for j in itertools.chain(range(0, low), range(high, dbc)):
                        assert block.set(j, bits[di + j])
                else:
                    for j in itertools.chain(range(0, low), range(high, dbc)):
                        locked_bits.add(j)

                targets_index = list(range(di, di+dbc))
                if not self._only_data:
                    targets_index.extend(range(eci, eci+ecbc))

                def compare(x):
                    t = self._targets[x]
                    if t.is_hard_zero():
                        if self._higher_first:
                            return INF
                        else:
                            return -1
                    else:
                        return t.contrast

                targets_index = sorted(targets_index, key=compare,
                                       reverse=self._higher_first)

                for target_index in targets_index:
                    target = self._targets[target_index]
                    point = target.point
                    fill = target.fill
                    if point.invert:
                        fill = not fill
                    if target.is_hard_zero():
                        fill = False
                    if point.type is QrPointType.DATA:
                        index = point.offset - di
                    else:
                        assert point.type is QrPointType.CORRECTION
                        index = point.offset - eci + dbc
                    if not self._only_data:
                        block.set(index, fill)
                    elif index not in locked_bits:
                        block[index] = fill

                if not self._only_data:
                    new_block_bits = block.bits()
                    data_bits.extend(new_block_bits, 0, dbc)
                    ec_bits.extend(new_block_bits, dbc, ecbc)
                else:
                    data_bits.extend(block)
                    ec_bits.extend(RSEncoder.encode(block, ecbc // 8, True))

                di += dbc
                eci += ecbc

            error_count = 0

            numbers = ''
            for i in range(0, numbers_count, 3):
                if i + 3 > numbers_count:
                    count = [None, 4, 7][numbers_count - i]
                else:
                    count = 10
                offset = used + i // 3 * 10
                value = Bits.copy_from(data_bits, offset, count)
                value = value.as_int
                if count == 10 and value >= 1000:
                    rand_pos = randint(0, 4)
                    hard_zero_pos = offset + rand_pos
                    self._targets[hard_zero_pos].set_hard_zero()
                    error_count += 1
                    value -= 2**(9 - rand_pos)
                elif count == 7 and value >= 100:
                    rand_pos = randint(0, 1)
                    hard_zero_pos = offset + rand_pos
                    self._targets[hard_zero_pos].set_hard_zero()
                    error_count += 1
                    value -= 2**(6 - rand_pos)
                elif count == 4 and value >= 10:
                    hard_zero_pos = offset
                    self._targets[hard_zero_pos].set_hard_zero()
                    error_count += 1
                    value -= 8
                numbers += str(value).rjust(count // 3, '0')

            print('Error count', error_count, end='')
            if error_count == 0:
                print(', send to printer.')
                data_bits.extend(ec_bits)
                self._bits = data_bits
                return data_bits
            else:
                print(', restart.')


================================================
FILE: pyqart/art/source.py
================================================
# Added at : 2016.8.2
# Author   : 7sDream
# Usage    : Source image to make QArt.

from random import randint

import PIL.Image as Image

from .target import Target
from ..qr.painter.point import QrPointType

__all__ = ['QArtSourceImage']


class QArtSourceImage(object):
    def __init__(self, path, left=None, top=None, size=None, board=None):
        """
        :param str|file path: Image file path or file-like object.
        :param int left: X of start point.
        :param int top: Y of start point.
        :param int size: Size of target image region.
        :param int board: Board region width.
        """
        self._img = Image.open(path)
        left = left or 0
        top = top or 0
        if size is None:
            size = min(self._img.width - left, self._img.height - top)
        self._set(left or 0, top or 0, size or 0, board or 0)
        self.path = path

    def _set(self, left, top, size, border):
        assert left >= 0, "left arg must > 0"
        assert top >= 0, "top arg must > 0"
        assert size >= 0, "size arg must >= 0"
        assert left + size <= self._img.width, "region over image"
        assert top + size <= self._img.height, "region over image"
        assert border >= 0, "border width must >= 0"
        self._left = int(left)
        self._top = int(top)
        self._size = int(size)
        self._border = int(border)

    def set_by_center(self, x, y, size, board):
        offset = (size - 1) // 2
        self._set(x - offset, y - offset, size, board)

    @staticmethod
    def _calc_divider(img):
        res = 0
        for row in range(img.height):
            for col in range(img.width):
                res += img.getpixel((row, col))
        n = img.width * img.height

        if n == 0:
            return 128

        return res // n

    @staticmethod
    def _calc_target_range(img, y, x, dy, dx):
        assert dy is None or dy > 0
        assert dx is None or dx > 0
        dx = dx or 3
        dy = dy or 3
        left = x - dx if x - dx >= 0 else 0
        right = x + dx + 1 if x + dx < img.width else img.width
        top = y - dy if y - dy >= 0 else 0
        bottom = y + dy + 1 if y + dy < img.height else img.height
        width = right - left
        height = bottom - top
        return left, right, top, bottom, width, height

    def _calc_contrast(self, img, y, x, dy, dx, rand):
        assert 0 <= y < img.height and 0 <= x < img.width, "Point out of image."
        assert isinstance(rand, bool)

        if rand:
            return randint(0, 128) + 64 * ((x + y) % 2) + 64 * ((x + y) % 3 % 2)

        l, r, t, b, w, h = self._calc_target_range(img, y, x, dy, dx)
        n = w * h
        sum_1 = sum_2 = 0
        for y in range(t, b):
            for x in range(l, r):
                v = img.getpixel((x, y))
                sum_1 += v
                sum_2 += v * v
        average = sum_1 / n

        return sum_2 / n - average * average

    def to_image(self, args, dither, dy, dx):
        assert dx is None or dx > 0, 'dx must >= 0.'
        assert dy is None or dy > 0, 'dy must >= 0.'

        code_part_size = self._size - 2 * self._border

        box_x, box_y = self._left + self._border, self._top + self._border
        box = (box_x, box_y, box_x + code_part_size, box_y + code_part_size)
        img = self._img.crop(box).resize((args.size, args.size))

        if dither:
            img = img.convert("1")
        else:
            img = img.convert('L')
            divider = self._calc_divider(img)
            img = img.point(lambda v: 0 if v <= divider else 255, '1')

        return img

    def to_targets(self, canvas, args, dither, rand, dy, dx):
        """
        :param QrCanvas canvas: canvas used to draw the QrCode.
        :param QrArgs args: The args of QrCode.
        :param bool dither: Make binary image with dithering or not.
        :param bool rand: Make contrast of target random number.
        :param int dy: Y offset when calc target.
        :param int dx: X offset when calc target.
        """
        temp = self.to_image(args, dither, dy, dx)

        targets = [None] * args.cwc * 8
        for y in range(temp.height):
            for x in range(temp.width):
                point = canvas.points[y][x]
                if point.type in {QrPointType.DATA, QrPointType.CORRECTION}:
                    fill = temp.getpixel((x, y)) == 0
                    contrast = self._calc_contrast(temp, y, x, dy, dx, rand)
                    targets[point.offset] = Target(y, x, fill, contrast, point)
        return targets


================================================
FILE: pyqart/art/target.py
================================================
# Added at : 2016.8.3
# Author   : 7sDream
# Usage    : Target point(contain point and image pixel info).

__all__ = ['Target']


class Target(object):
    def __init__(self, y, x, fill, contrast, point):
        self._y = y
        self._x = x
        self._fill = fill
        self._contrast = contrast
        self._point = point
        self._hard_zero = False

    @property
    def fill(self):
        return self._fill

    @property
    def contrast(self):
        return self._contrast

    @property
    def y(self):
        return self._y

    @property
    def x(self):
        return self._x

    @property
    def point(self):
        return self._point

    def set_hard_zero(self):
        self._hard_zero = True

    def is_hard_zero(self):
        return self._hard_zero

    def __str__(self):
        return "Target({fill}, {contrast:.3f})".format(
            fill=self.fill, contrast=self.contrast
        )


================================================
FILE: pyqart/common/__init__.py
================================================
from .bit_funcs import bit_at, set_bit, one_at, zero_at
from .bits import Bits
from .exception import InvalidTypeException

BIT_PER_CW = BIT_PER_BYTE = 8


================================================
FILE: pyqart/common/bit_funcs.py
================================================
# Added at  : 2016.07.28
# Author    : 7sDream
# Usage     : Some common function to process data.

import functools


__all__ = ['bit_at', 'one_at', 'zero_at', 'set_bit']


@functools.lru_cache()
def one_at(pos, size=8):
    """
    Create a size-bit int which only has one '1' bit at specific position.

    example:

    one_at(0) -> 0b10000000
    one_at(3) -> 0b00010000
    one_at(5, 10) -> 0b0000010000

    :param int pos: Position of '1' bit.
    :param int size: Length of value by bit.
    :rtype: int
    """
    assert 0 <= pos < size
    return 1 << (size - 1 - pos)


@functools.lru_cache()
def zero_at(pos, size=8):
    """
    Create a size-bit int which only has one '0' bit at specific position.

    :param int pos: Position of '0' bit.
    :param int size: Length of value by bit.
    :rtype: int
    """
    assert 0 <= pos < size
    return 2**size - 2**(size - pos - 1) - 1


def set_bit(value, pos, bit):
    """
    Set bit at specific position of a 8-bit value to '1' or '0'

    :param int value: Original value, 8 bit.
    :param int pos: Position of bit which will be set.
    :param bool bit: True for 1, False for 0.
    :return: New value
    :rtype: int
    """
    assert 0 <= pos < 8

    if bit:
        return value | one_at(pos)
    else:
        return value & zero_at(pos)


def bit_at(value, length, pos):
    """
    Get bit at pos of number, True for '1', False for '0':

    :param int value: Int value to get the bit.
    :param int length: Length of value by bit.
    :param int pos: Bit position, highest position is 0.
    :rtype: bool
    """

    assert length > 0
    assert 0 <= pos < length
    if value == 0:
        return False
    return ((value >> (length - 1 - pos)) & one_at(7)) == 1


================================================
FILE: pyqart/common/bits.py
================================================
# Added at : 2016.7.28
# Author   : 7sDream
# Usage    : A utility class provide some bit level operation to bit stream.

from .bit_funcs import set_bit, bit_at

__all__ = ['Bits']

_BIT_PER_BYTE = _BIT_PER_CW = 8

_PADDING_BITS = 0b1110110000010001
"""
padding with those data when data not fill data codewords.
"""


class Bits(object):
    def __init__(self, value=None, length=None):
        """
        Build a container that save value as a value_upper-bit size int.

        :param int value: Value to init the container.
        :value_upper int value_upper: Value value_upper by bit.
        """
        self._length = 0
        self._raw = bytearray(b'\x00')
        if value is not None:
            length = value.bit_length() if length is None else length
            self.append(value, length)

    @classmethod
    def copy_from(cls, other, start=0, count=None):
        """
        Build object from other :any:`Bits`.

        :param Bits|bytes|bytearray other: Target object.
        :param int start: Where to start copy.
        :param int count: How many data will be added.
            Default is None, will add all data.
        """
        obj = cls()
        obj.extend(other, start, count)
        return obj

    @property
    def length(self):
        """
        :return: Data value_upper by bit.
        :rtype: int
        """
        return self._length

    def __len__(self):
        return self.length

    @property
    def capacity(self):
        """
        :return: Capacity of object by bit.
        :return: int
        """
        return self.capacity_by_byte * _BIT_PER_BYTE

    @property
    def capacity_by_byte(self):
        """
        :return: Capacity of object by byte.
        :return: int
        """
        return len(self._raw)

    def append(self, value, length=None):
        """
        Add a value_upper-bit int to container's end, use lower data of value.

        :param int value: Value to be added.
        :param int length: Length of value by bit,
            default is None, which will use value.bit_length().
        """
        if length is None:
            length = value.bit_length()
        for i in range(length):
            self.append_bit(bit_at(value, length, i))

    def append_bit(self, bit):
        """
        Add one bit to container.

        :param bool bit: True for 1, False for 0
        """
        index = self.length
        self._expand_capacity(self._length + 1)
        self._length += 1
        self[index] = bit

    def extend(self, other, start=0, count=None):
        """
        Add new value from other Bits.

        :param Bits|bytes|bytearray other: Other data source want to be added.
        :param int start: Where to start copy, default is 0.
        :param int count: how many data will be extend.
            default is None, will add all data.
        :return: How many data be extended.
        :rtype: int
        """
        assert start >= 0
        if isinstance(other, Bits):
            end = len(other) if count is None else (start + count)
            end = min(end, len(other))
            for i in range(start, end):
                self.append_bit(other[i])
            return max(0, end - start)
        elif isinstance(other, (bytes, bytearray)):
            end = len(other) * _BIT_PER_BYTE \
                if count is None else (start + count)
            end = min(end, len(other) * _BIT_PER_BYTE)
            for i in range(start, end):
                self.append_bit(bit_at(
                    other[i // _BIT_PER_BYTE], _BIT_PER_BYTE,
                    i % _BIT_PER_BYTE))
            return max(0, end - start)
        return 0

    def xor(self, other, my_start=0, other_start=0, count=None):
        """
        [001010001] xor [0010110],
        self_start at 2 other_start at 3,
        value_upper 3 will be [00<101>0001] xor [001<011>0] -> [00<110>0001]

        :param Bit other: What to xor with.
        :param int my_start: Where to start be xor.
        :param int other_start: Where to start xor with.
        :param int count: How many data will be xor,
            default is None, will xor all possible.
        :return: How many data be xor.
        :rtype: int
        """
        my_end = self.length if count is None else (my_start + count)
        other_end = other.length if count is None else (other_start + count)
        my_end = min(self.length, my_end)
        other_end = min(other.length, other_end)
        count = 0
        for i, j in zip(range(my_start, my_end), range(other_start, other_end)):
            self[i] = self[i] ^ other[j]
            count += 1
        return count

    def pad(self, available, used):
        # add terminator
        self.append(0, min(available, 4))

        # add more 0s to make last several data to a codeword
        if self.length % _BIT_PER_CW != 0:
            self.append(0, _BIT_PER_CW - self.length % _BIT_PER_CW)

        # add pad bytes if the data is still not fill all data codewords
        available = available + used - self.length
        while available > 0:
            self.append(_PADDING_BITS, min(available, 16))
            available -= 16

    def _expand_capacity(self, target):
        """
        Expend capacity to ensure object can save "target" value_upper data.

        :param int target: Target capacity by bit
        """
        assert target >= 0
        while target > self.capacity:
            self._raw += b'\x00' * self.capacity_by_byte

    @property
    def as_int(self):
        """
        :return: View those data as int start at highest position,
            -1 if no data.
        :rtype: int
        """
        if self.length == 0:
            return -1
        return int(self.as_string, 2)

    @property
    def as_string(self):
        """
        :return: A string of "01" to represent those data.
            empty string if no data.
        :rtype: string
        """
        return ''.join(['1' if x else '0' for x in self])

    @property
    def as_bytes(self):
        return self._raw[:(self.length - 1) // _BIT_PER_BYTE + 1]

    @property
    def as_int_list(self):
        return [int(x) for x in self.as_bytes]

    def __str__(self):
        s = self.as_string
        return ', '.join([s[x:x + 8] for x in range(0, len(s), 8)])

    def __repr__(self):
        return "Bits at {id}: [{self}]".format(
            id=id(self),
            self=self,
        )

    def __iter__(self):
        for i in range(self.length):
            yield self[i]

    def __getitem__(self, index):
        if index >= self.length:
            raise IndexError()
        return bit_at(
            self._raw[index // _BIT_PER_BYTE],
            _BIT_PER_BYTE,
            index % _BIT_PER_BYTE
        )

    def __setitem__(self, index, value):
        if index >= self.length:
            raise IndexError()
        old_value = self._raw[index // _BIT_PER_BYTE]
        new_value = set_bit(old_value, index % _BIT_PER_BYTE, value)
        self._raw[index // _BIT_PER_BYTE] = new_value


================================================
FILE: pyqart/common/exception.py
================================================
# Added at  : 2016.07.30
# Author    : 7sDream
# Usage     : Exceptions raised by common functions or classes,


class InvalidTypeException(Exception):
    def __init__(self, excepted, given, index, function):
        self._excepted = excepted
        self._given = given
        self._function = function
        self._index = index + 1

    def __str__(self):
        string = "Invalid type at No.{number} argument of {function}, " \
                 "except {excepted}, {given} given."
        return string.format(
            index=self._index,
            function=self._function,
            excepted=self._excepted,
            given=self._given,
        )

    __repr__ = __str__


================================================
FILE: pyqart/qart_entry.py
================================================
import argparse
import sys
import time

from pyqart.art import QArtist
from pyqart.qr.printer import QrImagePrinter, QrStringPrinter


def main():
    parser = argparse.ArgumentParser(
        prog="pyqart",
        description="A program of generate QArt Codes.",
        epilog="Writen by 7sDream. (https://github.com/7sDream/pyqart)",
    )
    parser.add_argument(
        'url', type=str,
        help="url will be encode, like http://example.com/",
    )
    parser.add_argument(
        'img', type=str,
        help="target image the QrCode will look like",
    )
    parser.add_argument(
        '-s', '--start-point', type=int, nargs=2,
        help="left top point of the region of target image to use, "
             "default is (0, 0).",
    )
    parser.add_argument(
        '-w', '--region-width', type=int,
        help="target region width and height, "
             "default will make region as bigger as possible",
    )
    parser.add_argument(
        '-d', '--dither', action="store_true",
        help="dithering when generate binary target image",
    )
    parser.add_argument(
        '-y', '--only-data', action="store_true",
        help="only use data bit points to approach the target image",
    )
    parser.add_argument(
        '-n', '--rand', action="store_true",
        help="generate point contrast by random, "
             "if not provide, will use pixel nearby to calculate contrast",
    )
    parser.add_argument(
        '-f', '--higher-first', action='store_true',
        help="pick pixel from higher contrast region first, "
             "default will pick from lower region first"
    )
    parser.add_argument(
        '-x', '--yx', type=int, nargs=2,
        help="yx region when calculate contrast",
    )
    parser.add_argument(
        '-v', '--version', type=int,
        help="version of QrCode, 1 to 40, "
             "will auto calculated from data length if not provide",
    )
    parser.add_argument(
        '-l', '--level', type=int, default=0,
        help="QrCode error correction level, 0 to 3, default is 0",
    )
    parser.add_argument(
        '-m', '--mask', type=int,
        help="mask of QrCode, 0 to 7, default is random value",
    )
    parser.add_argument(
        '-r', '--rotation', type=int, default=0,
        help="rotate the QrCode(clockwise), "
             "0 for no rotation, 1 for 90 degree, 2 for 180, 3 for 270",
    )
    parser.add_argument(
        '-p', '--point-size', type=int, default=3,
        help="the point width and height of one QrCode point,"
             " by pixel, default is 3"
    )
    parser.add_argument(
        '-b', '--board', type=int,
        help="board wide by pixel, will auto calculated "
             "from code size if not provide",
    )
    parser.add_argument(
        '-c', '--color', type=int, nargs=3, metavar=('R', 'G', 'B'),
        help="front color of QrCode, 3 number as rgb color",
    )
    parser.add_argument(
        '-g', '--background-color', type=int, nargs=3, metavar=('R', 'G', 'B'),
        help="background color of QrCode, 3 number as rgb color",
    )
    parser.add_argument(
        '-o', '--output', type=str,
        help="output file path, code will print to terminal if not provide, "
             "and other arguments will be ignored"
    )

    argv = sys.argv[1:]

    args = parser.parse_args(argv)

    if args.yx is None:
        args.yx = [None, None]
    if args.color is not None:
        args.color = tuple(args.color)
    if args.background_color is not None:
        args.background_color = tuple(args.background_color)

    start = time.time()

    artist = QArtist(args.url, args.img, args.version, args.mask, args.level,
                     args.rotation, args.dither, args.only_data, args.rand,
                     args.yx[0], args.yx[1])

    if args.output is not None:
        QrImagePrinter.print(
            artist, args.output, args.point_size, args.board,
            args.color, args.background_color
        )
        print('Done.')
    else:
        QrStringPrinter.print(artist, True)

    end = time.time()
    print("Used time:", end-start, 'second.')

if __name__ == '__main__':
    main()


================================================
FILE: pyqart/qr/__init__.py
================================================
from .args import QrArgs
from .data import (
    QrData,
    QrDataInvalidException,
    QrEncodingException,
    QrSpaceNotEnoughException
)
from .painter import QrPainter, QrCanvasException, QrPainterException
from .printer import (
    QrBasePrinter, QrImagePrinter, QrStringPrinter, QrHalftonePrinter
)
from .exception import QrException


================================================
FILE: pyqart/qr/args/__init__.py
================================================
from .args import QrArgs


================================================
FILE: pyqart/qr/args/args.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : All needed args to create a empty qr code.

from .mask import QrMask
from .version import QrVersion
from .rotation import QrRotation
from ..data import Raw, AlphaNumeric, Numbers
from ...common import Bits

__all__ = ['QrArgs']

_FORMAT_POLY = Bits(0x537, 11)
"""
  x^10 + x^8 + x^5 + x^4 + x^2 + x + 1
= 1    0  1 00 1     1   0 1    1   1
= 0101 0011 0111
= 0x573

Used when calculate format pattern data.
"""

_FORMAT_MASK_PATTERN = Bits(0x5412, 15)
"""
After all, format data should be xor with this mask pattern.
"""

_BC_ECCWCPB_TABLE = [
    [(1, 7), (1, 10), (1, 13), (1, 17)],
    [(1, 10), (1, 16), (1, 22), (1, 28)],
    [(1, 15), (1, 26), (2, 18), (2, 22)],
    [(1, 20), (2, 18), (2, 26), (4, 16)],
    [(1, 26), (2, 24), (4, 18), (4, 22)],
    [(2, 18), (4, 16), (4, 24), (4, 28)],
    [(2, 20), (4, 18), (6, 18), (5, 26)],
    [(2, 24), (4, 22), (6, 22), (6, 26)],
    [(2, 30), (5, 22), (8, 20), (8, 24)],
    [(4, 18), (5, 26), (8, 24), (8, 28)],
    [(4, 20), (5, 30), (8, 28), (11, 24)],
    [(4, 24), (8, 22), (10, 26), (11, 28)],
    [(4, 26), (9, 22), (12, 24), (16, 22)],
    [(4, 30), (9, 24), (16, 20), (16, 24)],
    [(6, 22), (10, 24), (12, 30), (18, 24)],
    [(6, 24), (10, 28), (17, 24), (16, 30)],
    [(6, 28), (11, 28), (16, 28), (19, 28)],
    [(6, 30), (13, 26), (18, 28), (21, 28)],
    [(7, 28), (14, 26), (21, 26), (25, 26)],
    [(8, 28), (16, 26), (20, 30), (25, 28)],
    [(8, 28), (17, 26), (23, 28), (25, 30)],
    [(9, 28), (17, 28), (23, 30), (34, 24)],
    [(9, 30), (18, 28), (25, 30), (30, 30)],
    [(10, 30), (20, 28), (27, 30), (32, 30)],
    [(12, 26), (21, 28), (29, 30), (35, 30)],
    [(12, 28), (23, 28), (34, 28), (37, 30)],
    [(12, 30), (25, 28), (34, 30), (40, 30)],
    [(13, 30), (26, 28), (35, 30), (42, 30)],
    [(14, 30), (28, 28), (38, 30), (45, 30)],
    [(15, 30), (29, 28), (40, 30), (48, 30)],
    [(16, 30), (31, 28), (43, 30), (51, 30)],
    [(17, 30), (33, 28), (45, 30), (54, 30)],
    [(18, 30), (35, 28), (48, 30), (57, 30)],
    [(19, 30), (37, 28), (51, 30), (60, 30)],
    [(19, 30), (38, 28), (53, 30), (63, 30)],
    [(20, 30), (40, 28), (56, 30), (66, 30)],
    [(21, 30), (43, 28), (59, 30), (70, 30)],
    [(22, 30), (45, 28), (62, 30), (74, 30)],
    [(24, 30), (47, 28), (65, 30), (77, 30)],
    [(25, 30), (49, 28), (68, 30), (81, 30)],
]
"""
Table of (block count, error correction codeword count per block).
Row by version, column by level.
"""


CCI_LENGTH_TABLE = {
    Raw: [(9, 8), (40, 16)],
    AlphaNumeric: [(9, 9), (26, 11), (40, 13)],
    Numbers: [(9, 10), (26, 12), (40, 14)]
}
"""
When data encoding, the Char Count Indicator value_upper table.

if version <= first_item, cci_length is second_item.
"""


class QrArgs(object):
    def __init__(self, version, level=0, mask=0, rotation=0):
        assert 0 <= level <= 3, "Level must between 0 and 3."
        self._version = QrVersion(version)
        self._mask = QrMask(mask)
        self._level = level
        self._rotation = QrRotation(rotation)

    @property
    def size(self):
        """
        :return: Width and height of QrCode.
        :rtype: int
        """
        return self._version.size

    @property
    def rotate_func(self):
        return self._rotation.rotate_func

    @property
    def align_start(self):
        """
        :return: See :any:`QrVersion.align_start`.
        :rtype: int
        """
        return self._version.align_start

    @property
    def align_step(self):
        """
        :return: See :any:`QrVersion.align_step`.
        :rtype: int
        """
        return self._version.align_step

    @property
    def version_pattern_value(self):
        """
        :return: See :any:`QrVersion.version_pattern_value`.
        :rtype: int
        """
        return self._version.version_pattern_value

    @property
    def version_number(self):
        """
        :return: See :any:`QrVersion.number`.
        :rtype: int
        """
        return self._version.number

    @property
    def level(self):
        """
        :return: See :any:`QrLevel.index`.
        :rtype: int
        """
        return self._level

    @property
    def mask_index(self):
        """
        :return: See :any:`QrMask.index`.
        :rtype: int
        """
        return self._mask.index

    @property
    def format_pattern_bits(self):
        """
        Format pattern has 15 bit,
        split to 3 parts: level, mask, error correction.

        It's structure like bellow:

        14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

        Lv Lv M  M  M  C C C C C C C C C C

        Level part value table:

        ---- ----------- ---------
        name index value bit value
        ---- ----------- ---------
         L        00         01
         M        01         00
         H        10         11
         Q        11         10
        ---- ----------- ---------

        We can see: bit value = index value xor 01, 2 bit

        QrMask from 0(000) to 7(111), 3 bit

        Correction data is calculated by bch(15, 5), 10 bit

        :return: The format pattern value in a :any:`Bits` object.
        :rtype: Bits
        """
        # level
        bits = Bits(self.level ^ 0b01, 2)
        # mask
        bits.append(self.mask_index, 3)
        # ec
        bits.append(0, 10)
        ec = Bits.copy_from(bits)
        for i in range(5):
            if ec[i]:
                ec.xor(_FORMAT_POLY, i, 0)
        for i in range(5, 15):
            bits[i] = ec[i]
        # masking
        bits.xor(_FORMAT_MASK_PATTERN)
        return bits

    @property
    def bc(self):
        """
        :return: Block count.
        :rtype: int
        """
        return _BC_ECCWCPB_TABLE[self.version_number - 1][self.level][0]

    @property
    def eccwcpb(self):
        """
        :return: Error Correction CodeWord Count Per Block.
        :return: int
        """
        return _BC_ECCWCPB_TABLE[self.version_number - 1][self.level][1]

    @property
    def cwc(self):
        """
        :return: See :any:`QrVersion.cwc`.
        :rtype: int
        """
        return self._version.cwc

    @property
    def eccwc(self):
        """
        :return: Error Correction CodeWord Count
        :rtype: int
        """
        return self.eccwcpb * self.bc

    @property
    def dcwc(self):
        """
        :return: Data CodeWord Count.
        :rtype: int
        """
        return self.cwc - self.eccwc

    @property
    def ndcwcpb(self):
        """
        :return: Normal Data CodeWord Count Per Block.
        :rtype: int
        """
        return self.dcwc // self.bc

    @property
    def edcwc(self):
        """
        :return: Extra Data CodeWord Count.
        :rtype: int
        """
        return self.dcwc - self.ndcwcpb * self.bc

    def dcwcof(self, index):
        """
        :param int index: Block index.
        :return: Data CodeWord Count OF No.index block.
        :rtype: int
        """
        assert index < self.bc
        return self.ndcwcpb + (0 if index < (self.bc - self.edcwc) else 1)

    @property
    def should_invert(self):
        """
        :return: See :any:`QrMask.should_invert`.
        :rtype: callable
        """
        return self._mask.should_invert

    def cci_length_of(self, cls):
        for sep, value in CCI_LENGTH_TABLE[cls]:
            if self.version_number <= sep:
                return value


================================================
FILE: pyqart/qr/args/mask.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : QrMask represent data part mask of QrCode,
#            which changes which modules are dark and which are light
#            according to a particular rule.
#            The purpose of this step is to modify the QR code to make it
#            as easy for a QR code reader to scan as possible.
#            There are only 8 mask pattern can be used.

__all__ = ['QrMask']

_FUNCTION_LIST = [
    lambda y, x: (x + y) % 2 == 0,
    lambda y, x: y % 2 == 0,
    lambda y, x: x % 3 == 0,
    lambda y, x: (x + y) % 3 == 0,
    lambda y, x: (y // 2 + x // 3) % 2 == 0,
    lambda y, x: x * y % 2 + x * y % 3 == 0,
    lambda y, x: (x * y % 2 + x * y % 3) % 2 == 0,
    lambda y, x: ((x + y) % 2 + (x * y) % 3) % 2 == 0,
]
"""
The mask function table.
"""


class QrMask(object):
    def __init__(self, mask_index):
        assert 0 <= mask_index <= 7, "Mask must between 0 and 7"
        self._index = mask_index

    @property
    def index(self):
        """
        :return: Mask index, from 0 to 7, specific the mask pattern.
        :rtype: int
        """
        return self._index

    @property
    def should_invert(self):
        """
        :return: A function accept (y, x) to decide if point should invert.
        :rtype: callable
        """
        return _FUNCTION_LIST[self.index]


================================================
FILE: pyqart/qr/args/rotation.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : QrRotation represent the rotate of QrCode:
#               0 for rotate 0 degrees clockwise, 1 for 90, 2 to 180, 3 for 270.

__all__ = ['QrRotation']

_ROTATE_FUNC_LIST = [
    None,
    lambda y, x, s: (x, s-y-1),
    lambda y, x, s: (s-y-1, s-x-1),
    lambda y, x, s: (s-x-1, y)
]


class QrRotation(object):
    def __init__(self, rotate_index):
        assert 0 <= rotate_index <= 3, "Rotation must between 0 and 3."
        self._index = rotate_index

    @property
    def index(self):
        return self._index

    @property
    def rotate_func(self):
        return _ROTATE_FUNC_LIST[self.index]


================================================
FILE: pyqart/qr/args/version.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : QrVersion represent version of QrCode, which decide:
#               code's size,
#               value_upper codeword count,
#               align pattern position,
#               version pattern value.

__all__ = ['QrVersion']

_ALIGN_START_TABLE = [
    100, 16, 20, 24, 28, 32, 20, 22, 24, 26,
    28, 30, 32, 24, 24, 24, 28, 28, 28, 32,
    26, 24, 28, 26, 30, 28, 32, 24, 28, 24,
    28, 32, 28, 32, 28, 22, 26, 30, 24, 28,
]

_ALIGN_STEP_TABLE = [
    100, 100, 100, 100, 100, 100, 16, 18, 20, 22,
    24, 26, 28, 20, 22, 24, 24, 26, 28, 28,
    22, 24, 24, 26, 26, 28, 28, 24, 24, 26,
    26, 26, 28, 28, 24, 26, 26, 26, 28, 28,
]

_VERSION_PATTERN_VALUE_TABLE = [
    0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x7c94, 0x85bc, 0x9a99, 0xa4d3,
    0xbbf6, 0xc762, 0xd847, 0xe60d, 0xf928,
    0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6,
    0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1,
    0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
    0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f,
    0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69,
]

_CODEWORD_COUNT_TABLE = [
    26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
    404, 466, 532, 581, 655, 733, 815, 901, 991, 1085,
    1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185,
    2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706,
]


class QrVersion(object):
    def __init__(self, version_number):
        assert 1 <= version_number <= 40, "Version must between 1 and 40."
        self._num = version_number

    @property
    def number(self):
        """
        :return: The number represent of the version, from 1 to 40.
        :rtype: int
        """
        return self._num

    @property
    def size(self):
        return 17 + 4 * self._num

    @property
    def align_start(self):
        return _ALIGN_START_TABLE[self.number - 1]

    @property
    def align_step(self):
        return _ALIGN_STEP_TABLE[self.number - 1]

    @property
    def version_pattern_value(self):
        return _VERSION_PATTERN_VALUE_TABLE[self.number - 1]

    @property
    def cwc(self):
        """
        CodeWord Count
        """
        return _CODEWORD_COUNT_TABLE[self.number - 1]


================================================
FILE: pyqart/qr/data/__init__.py
================================================
from .data import QrData
from .raw import Raw
from .numbers import Numbers
from .alphanumeric import AlphaNumeric

from .exception import (
    QrDataInvalidException,
    QrEncodingException,
    QrSpaceNotEnoughException,
)


================================================
FILE: pyqart/qr/data/alphanumeric.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : Data mode that used to encode
#            big alpha (A-Z)
#            and numeric (0-9)
#            and some special symbols (space, $, %, *, +, -, ., /, :).

from .exception import QrDataInvalidException
from .base import BaseType
from ...common import Bits

__all__ = ['AlphaNumeric']

_ALPHA_NUMERIC_TABLE = {
    ''.join([chr(c) for c in range(ord('0'), ord('9') + 1)]):
        lambda c: int(c),
    ''.join([chr(c) for c in range(ord('A'), ord('Z') + 1)]):
        lambda c: ord(c) - ord('A') + 10,
    ' $%*+-./:':
        lambda c: ' $%*+-./:'.index(c) + 36
}

_DOMAIN = ''
for key in _ALPHA_NUMERIC_TABLE.keys():
    _DOMAIN += key


class AlphaNumeric(BaseType):
    def __init__(self, data, cci_length):
        super().__init__(data, cci_length)

    @property
    def _mode_indicator(self):
        return 0b0010

    def _validate(self):
        for i, v in enumerate(self.data):
            if v not in _DOMAIN:
                raise QrDataInvalidException(
                    type(self).__name__,
                    self.data,
                    i,
                )

    @property
    def _encoded_data_part(self):
        bits = Bits()
        for i in range(0, len(self.data), 2):
            part = self.data[i:i + 2]
            if len(part) == 2:
                a, b = tuple(part)
                length = 11
            else:
                a, b = part[0], None
                length = 6
            bits.append(self._calc_number(a, b), length)
        return bits

    @staticmethod
    def _calc_number(a, b=None):
        number1 = number2 = -1
        for k, func in _ALPHA_NUMERIC_TABLE.items():
            if a in k:
                number1 = func(a)
            if b is not None and b in k:
                number2 = func(b)
        if b is None:
            return number1
        else:
            return number1 * 45 + number2

    @property
    def _encoded_data_part_length(self):
        return 11 * (len(self.data) // 2) + 6 * (len(self.data) % 2)


================================================
FILE: pyqart/qr/data/base.py
================================================
# Added at : 2016.7.28
# Author   : 7sDream
# Usage    : A base data mode class for encoding data to bytes.
#            All specific data model inherit from this class.

import abc

from ...common import Bits
from .exception import QrEncodingException

__all__ = ['BaseType']


class BaseType(object):
    def __init__(self, data, cci_length):
        """
        :param data: Data to be encoded
        :param int cci_length: value_upper of Char Count Indicator in bit
        """
        assert len(data) > 0, 'Unable to encode empty data.'
        self._data = data
        self._cci_length = cci_length
        self._validate()

    @property
    def data(self):
        """
        :return: provided, raw original data
        """
        return self._data

    @property
    @abc.abstractmethod
    def _encoded_data_part_length(self):
        return 0

    @property
    def needed_space(self):
        return 4 + self._cci_length + self._encoded_data_part_length

    @property
    @abc.abstractmethod
    def _mode_indicator(self):
        """
        :return: A 4-bit data to indicate what model is using,
            Use the lower 4 data.
        :rtype: int
        """
        pass

    @property
    def _char_count_indicator(self):
        """
        :return: Placed before encoded data to indicate data value_upper,
            it's own value_upper is decided by :any:`cci_length`.
        :rtype: Bits
        """
        bits = Bits()
        bits.append(0, self._cci_length - len(self.data).bit_length())
        bits.append(len(self.data), len(self.data).bit_length())
        return bits

    @abc.abstractmethod
    def _validate(self):
        """
        validate data, raise :any:`QrDataInvalidException`
        if data is invalid, implemented by subclasses.

        :raise: QrDataInvalidException
        """
        pass

    @property
    @abc.abstractmethod
    def _encoded_data_part(self):
        """
        encode data to bytes use specific model, implemented by subclasses.

        :return: encoded data
        :rtype: Bits
        """
        pass

    @property
    def output(self):
        """
        :return: Output encoded data.
        :rtype: Bits
        """
        bits = Bits()
        bits.append(self._mode_indicator, 4)
        bits.extend(self._char_count_indicator)
        bits.extend(self._encoded_data_part)
        if bits.length != self.needed_space:
            raise QrEncodingException(
                type(self), self.data,
                info="Encoded data value_upper does not match expectations.",
                exception=self.needed_space,
                actual=bits.length,
            )
        return bits

    def __str__(self):
        mi = Bits()
        mi.append(self._mode_indicator, 4)
        cci = Bits()
        cci.extend(self._char_count_indicator)
        encoded_data = Bits()
        encoded_data.extend(self._encoded_data_part)

        string = "{type} at {id:x}: " \
                 "{{data: {data}, mi: {mi}, cci: {cci}, encode: {code}}}"
        return string.format(
            type=type(self).__name__, id=id(self),
            data=self.data, mi=mi, cci=cci, code=encoded_data,
        )


================================================
FILE: pyqart/qr/data/data.py
================================================
# Added at : 2016.7.30
# Author   : 7sDream
# Usage    : As a data set of (maybe) different data mode thad will be encoded.

from .raw import Raw
from .alphanumeric import AlphaNumeric
from .numbers import Numbers
from .exception import QrSpaceNotEnoughException
from ...common import BIT_PER_CW


class QrData(object):
    def __init__(self, string=None, ec_level=0):
        from ..args import QrArgs
        assert isinstance(string, str)
        assert 0 <= ec_level <= 3
        self._data_set = []
        self._ec_level = ec_level
        self._changed = False
        self._last = (1, QrArgs(1).dcwc * BIT_PER_CW, 0)

        if string is not None:
            self.put_string(string)

    @property
    def size(self):
        """
        :return: How many data item in object.
        :rtype: int
        """
        return len(self._data_set)

    @property
    def version_used_available(self):
        from ..args import QrArgs
        if self._changed is True:
            args = None
            used = 0
            for i in range(1, 41):
                args = QrArgs(i, self._ec_level)
                encode_list = [cls(data, args.cci_length_of(cls))
                               for cls, data in self._data_set]
                used = sum([x.needed_space for x in encode_list])
                available = args.dcwc * BIT_PER_CW - used
                if available >= 0:
                    self._last = (i, available, used)
                    self._changed = False
                    break
            else:
                raise QrSpaceNotEnoughException(
                    args.dcwc * BIT_PER_CW, used
                )
        return self._last

    @property
    def ec_level(self):
        return self._ec_level

    def set_level(self, level):
        assert 0 <= level <= 3
        if self._ec_level != level:
            self._ec_level = level
            self._changed = True

    def _common_put(self, data, cls):
        if len(self._data_set) > 0 and self._data_set[-1][0] is cls:
            old_data = self._data_set[-1][1]
            self._data_set[-1] = (cls, old_data + data)
        else:
            self._data_set.append((cls, data))
        self._changed = True

    def put_string(self, string):
        """
        Add string(utf-8) data to QrCode.

        :param str string: The string will be added.
        :return: A tuple: (if_success, exception).
        :rtype: (bool, QrException)
        :raise: QrDataInvalidException
        """
        return self._common_put(string.encode('utf-8'), Raw)

    def put_bytes(self, data):
        """
        Add raw bytes data to QrCode.

        :see-also:: :any:`put_string` for return and exception info.
        """
        return self._common_put(data, Raw)

    def put_numbers(self, numbers):
        """
        Add numbers data to QrCode.

        :see-also:: :any:`put_string` for return and exception info.

        :param int|str numbers: The number will be added,
            0 start at string type numbers will be preserved.
        """
        return self._common_put(numbers, Numbers)

    def put_alpha_numeric(self, string):
        """
        Add numbers, big letters, and some special symbol data to QrCode.

        :see-also:: :any:`put_string` for return and exception info.

        :param str string: The data will be added.
        """
        return self._common_put(string, AlphaNumeric)

    @property
    def data_set(self):
        return tuple(self._data_set)


================================================
FILE: pyqart/qr/data/exception.py
================================================
# Added at : 2016.7.28
# Author   : 7sDream
# Usage    : Exception when encode data is not invalid.

from ..exception import QrException

__all__ = ['QrDataInvalidException', 'QrEncodingException',
           'QrSpaceNotEnoughException']


class QrDataInvalidException(QrException):
    def __init__(self, typename, invalid_data, index=None):
        self.typename = typename
        self.invalid_data = invalid_data
        self.index = index

    def __str__(self):
        string = "Invalid data \"{data}\" when build a {typename} data mode."
        if self.index is not None:
            string += " first invalid position is {number}."
        return string.format(
            data=self.invalid_data,
            typename=self.typename,
            index=self.index,
        )

    __repr__ = __str__


class QrEncodingException(QrException):
    def __init__(self, cls, data, **kwargs):
        self._cls = cls
        self._data = data
        self._kwargs = kwargs

    def __str__(self):
        string = "Error when encoding {cls}] type data [{data}]."
        if len(self._kwargs) > 0:
            string += 'Additional information: ' + str(self._kwargs)


class QrSpaceNotEnoughException(QrException):
    def __init__(self, available, need):
        self._available = available
        self._needed = need

    def __str__(self):
        string = "There is not enough space to store the data provided, "
        string += "{available} bit space available, data need {need} bit."
        return string.format(
            available=self._available,
            need=self._needed
        )

    __repr__ = __str__


================================================
FILE: pyqart/qr/data/numbers.py
================================================
# Added at : 2016.7.28
# Author   : 7sDream
# Usage    : Numbers data model, 10 bit for 3 numbers.

from .base import BaseType
from ...common import Bits
from .exception import QrDataInvalidException


class Numbers(BaseType):
    def __init__(self, data, cci_length):
        super().__init__(data, cci_length)

    def _validate(self):
        for i, value in enumerate(self.data):
            if not ord('0') <= ord(value) <= ord('9'):
                raise QrDataInvalidException(
                    type(self).__name__, self.data, i)

    @property
    def _encoded_data_part(self):
        bits = Bits()
        split = (self.data[x:x + 3] for x in range(0, len(self.data), 3))
        for i, string in enumerate(split):
            bits.append(int(string), 1 + 3 * len(string))
        return bits

    @property
    def _mode_indicator(self):
        return 0b0001

    @property
    def _encoded_data_part_length(self):
        return 10 * (len(self.data) // 3) + [0, 4, 7][len(self.data) % 3]


================================================
FILE: pyqart/qr/data/raw.py
================================================
# Added at : 2016.7.28
# Author   : 7sDream
# Usage    : Raw data model, 8 bit for a byte.

from .base import BaseType
from .exception import QrDataInvalidException
from ...common import Bits

__all__ = ['Raw']


class Raw(BaseType):
    def __init__(self, data, cci_length):
        super().__init__(data, cci_length)

    @property
    def _encoded_data_part(self):
        bits = Bits()
        bits.extend(self.data)
        return bits

    @property
    def _mode_indicator(self):
        return 0b0100

    def _validate(self):
        for i, value in enumerate(self.data):
            if value < 0 or value > 255:
                raise QrDataInvalidException(
                    type(self).__name__,
                    self.data,
                    i,
                )

    @property
    def _encoded_data_part_length(self):
        return 8 * len(self.data)


================================================
FILE: pyqart/qr/ec/__init__.py
================================================
from .rsencoder import RSEncoder


================================================
FILE: pyqart/qr/ec/gf.py
================================================
# Added at : 2016.7.31
# Author   : 7sDream
# Usage    : Calculate GF(2^m) and all it's item a^n

from ...common import bit_at

__all__ = ['GF28']

_MUL_CACHE = {}
_ADD_CACHE = {}


class _GF2M(object):
    def __init__(self, m, px):
        self._m = m
        self._px = px % self.value_upper
        self._table, self._rev_table = self.calc()

    @property
    def value_upper(self):
        return 2 ** self._m

    @property
    def index_upper(self):
        return self.value_upper

    def calc(self):
        table = []
        rev_table = [None] * self.value_upper
        for x in range(self.index_upper):
            if x < self._m:
                value = 1 << x
            elif x == self._m:
                value = self._px
            elif not bit_at(table[-1], self._m, 0):
                value = (table[-1] << 1) % self.value_upper
            else:
                value = (table[-1] << 1 ^ self._px) % self.value_upper
            table.append(value)
            try:
                rev_table[value] = x
            except Exception as e:
                print(value)
                raise e
        table.append(1)
        return table, rev_table

    def index(self, value):
        return self._rev_table[value]

    def __getitem__(self, index):
        return _GFItem(self, index, self._table[index])


class _GFItem(object):
    def __init__(self, gf, index, value):
        self._gf = gf
        self._index = index
        self._value = value

    @property
    def gf(self):
        return self._gf

    @property
    def index(self):
        return self._index

    @property
    def value(self):
        return self._value

    def __add__(self, other):
        cache_index = (self.gf, self.index, other.index)
        if cache_index not in _ADD_CACHE:
            value = self._value ^ other.value
            if value == 0:
                return None
            item = _GFItem(self.gf, self.gf.index(value), value)
            _ADD_CACHE[cache_index] = item
        else:
            item = _ADD_CACHE[cache_index]
        return item

    def __mul__(self, other):
        cache_index = (self.gf, self.index, other.index)
        if cache_index not in _MUL_CACHE:
            index = self.index + other.index
            index = index % self.gf.value_upper + int(index // self.gf.value_upper)
            item = self.gf[index]
            _MUL_CACHE[cache_index] = item
        else:
            item = _MUL_CACHE[cache_index]
        return item

    def __str__(self):
        return "a" + str(self.index)


GF28 = _GF2M(8, 0b100011101)


================================================
FILE: pyqart/qr/ec/poly.py
================================================
# Added at  : 2016.07.31
# Author    : 7sDream
# Usage     : Provide math operator with polynomials on GF28.
#               Used in Reed-solomon encoder.

import abc

from .gf import GF28

__all__ = ['GF28Poly']


class _GFPoly(object):
    @classmethod
    @abc.abstractmethod
    def gf(cls):
        pass

    def __init__(self, pcmap):
        self._pcmap = pcmap
        if self._pcmap:
            self._max_index = max(self._pcmap.keys())
        else:
            self._max_index = 0

    @classmethod
    def from_index_list(cls, ilist, maxp):
        pcmap = {}
        for xi, ai in enumerate(ilist):
            if ai is None:
                continue
            pcmap[maxp - xi] = cls.gf()[ai]
        return cls(pcmap)

    @classmethod
    def from_value_list(cls, vlist, maxp):
        pcmap = {}
        for i, v in enumerate(vlist):
            if v == 0:
                continue
            pcmap[maxp - i] = cls.gf()[cls.gf().index(v)]
        return cls(pcmap)

    @property
    def pcmap(self):
        return self._pcmap

    @property
    def max_index(self):
        return self._max_index

    @property
    def as_int_list(self):
        int_list = []
        for p in reversed(range(self.max_index + 1)):
            if p in self.pcmap:
                int_list.append(self.pcmap[p].value)
            else:
                int_list.append(0)
        return int_list

    def __mul__(self, other):
        new_pcmap = {}
        for p1, c1 in self.pcmap.items():
            for p2, c2 in other.pcmap.items():
                if (p1 + p2) in new_pcmap:
                    old_value = new_pcmap[p1 + p2]
                    new_pcmap[p1 + p2] = old_value + c1 * c2
                else:
                    new_pcmap[p1 + p2] = c1 * c2
        return type(self)(new_pcmap)

    def __mod__(self, other):
        r = type(self)(self.pcmap)
        while r.max_index >= other.max_index:
            pad = r.max_index - other.max_index
            pad_item = type(self)({pad: r.pcmap[r.max_index]})
            r += other * pad_item
        return r

    def __add__(self, other):
        pcmap = {}
        for p in range(max(self.max_index, other.max_index) + 1):
            if p in self.pcmap:
                pcmap[p] = self.pcmap[p]
            if p in other.pcmap:
                if p in pcmap:
                    pcmap[p] += other.pcmap[p]
                else:
                    pcmap[p] = other.pcmap[p]
                if pcmap[p] is None:
                    del pcmap[p]
        return type(self)(pcmap)

    def __str__(self):
        pc_list = sorted(self.pcmap.items(), key=lambda x: x[0], reverse=True)
        strings = []
        for p, c in pc_list:
            if p == 0:
                item = str(c)
            elif p == 1:
                item = str(c) + 'x'
            else:
                item = str(c) + 'x^' + str(p)
            strings.append(item)
        return '+'.join(strings)

    def __repr__(self):
        return "Poly at {id}: {string}".format(id=id(self), string=str(self))


class GF28Poly(_GFPoly):
    @classmethod
    def gf(cls):
        return GF28


================================================
FILE: pyqart/qr/ec/rsencoder.py
================================================
from .poly import GF28Poly
from ...common import Bits


class _RSGenPolynomials(object):
    def __init__(self):
        self._table = [None, GF28Poly.from_index_list([0, 0], 1)]

    def __getitem__(self, index):
        while index > len(self._table) - 1:
            c = len(self._table) - 1
            self._table.append(
                self._table[-1] * GF28Poly.from_index_list([0, c], 1))
        return self._table[index]


RSGenPolynomials = _RSGenPolynomials()


class RSEncoder(object):
    @classmethod
    def encode(cls, data, ec_length, need_bits=True):
        assert ec_length >= 0
        if ec_length == 0:
            return Bits()
        if not isinstance(data, list):
            data = data.as_int_list
        data_length = len(data)
        all_length = ec_length + data_length
        m = GF28Poly.from_value_list(
            data + [0] * ec_length,
            all_length - 1
        )
        g = RSGenPolynomials[ec_length]
        r = m % g
        res = r.as_int_list
        if len(res) < ec_length:
            res = [0] * (ec_length - len(res)) + res
        if need_bits:
            return Bits.copy_from(bytearray(res))
        else:
            return res



================================================
FILE: pyqart/qr/exception.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : Base exception.

__all__ = ['QrException']


class QrException(Exception):
    pass


================================================
FILE: pyqart/qr/painter/__init__.py
================================================
from .painter import QrPainter
from .exception import QrCanvasException, QrPainterException


================================================
FILE: pyqart/qr/painter/canvas.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : A canvas to draw the QrCode. It implements function to draw
#            a basic QrCode whose data part is empty from QrArgs.

from .exception import QrCanvasException
from .point import QrPoint, QrPointType
from ..args import QrArgs

__all__ = ['QrCanvas']

_TYPE_CHAR_MAP = {
    QrPointType.UNKNOWN: '? ',
    QrPointType.POSITION: 'Q*',
    QrPointType.ALIGNMENT: 'A^',
    QrPointType.TIMING: 'T-',
    QrPointType.FORMAT: 'F<',
    QrPointType.VERSION_PATTERN: 'V+',
    QrPointType.UNUSED: 'Nu',
    QrPointType.DATA: '@.',
    QrPointType.CORRECTION: '#,',
    QrPointType.EXTRA: 'E~',
}
"""
The char table use to convert QrCode to string to print.
"""

_BIT_PER_CW = 8


class QrCanvas(object):
    def __init__(self, args):
        assert isinstance(args, QrArgs), "args argument must be QrArgs object."
        self._args = args
        self._size = self.args.size
        self._points = [
            [QrPoint(False) for _ in range(self.size)]
            for _ in range(self.size)]

        self._add_timing_pattern()
        self._add_position_patterns()
        self._add_align_patterns()
        self._add_version_pattern()
        self._add_unused_point()
        self._add_format_pattern()
        self._data_ec_points = self._add_empty_data_ec()
        self._add_mask()
        self._rotate()

    def _add_timing_pattern(self):
        """
        Add timing line to point array,  like bellow

          0 1 2 3 4 5 6 7 8 9 ... -- x axis
        0             @
        1             .
        2             @
        3             .
        4             @
        5             .
        6 @ . @ . @ . @ . @ . @ . @ . @ . @ . @ . @ . @ ....
        7             .
        8             @
        9             .
        10            @
        11            .
        12            @
        13           ...
        |
        y axis

        The (0-6, 6) and (6, 0-5) part will be override by position box.
        """
        # rol 6 and col 6 is timing version_pattern_value
        timing_position = 6
        for i in range(self.size):
            self._points[i][timing_position].type = QrPointType.TIMING
            self._points[timing_position][i].type = QrPointType.TIMING
            if i % 2 == 0:
                self._points[i][timing_position].fill = True
                self._points[timing_position][i].fill = True

    def _add_position_patterns(self):
        self._add_position_pattern(0, 0)
        self._add_position_pattern(0, self.size - 7)
        self._add_position_pattern(self.size - 7, 0)

    def _add_align_patterns(self):
        first_special_pos = 4
        start = self.args.align_start
        step = self.args.align_step
        size = self.size
        y = first_special_pos
        while y + 5 < size:
            x = first_special_pos
            while x + 5 < size:
                if self._check_align_box_position(y, x):
                    self._add_align_pattern(y, x)
                x = start if x == first_special_pos else (x + step)
            y = start if y == first_special_pos else (y + step)

    def _add_version_pattern(self):
        version_block_pattern = self.args.version_pattern_value
        if version_block_pattern != 0:
            for x in range(6):
                for y in range(3):
                    point_a = self._points[self.size - 11 + y][x]
                    point_b = self._points[x][self.size - 11 + y]
                    point_a.type = point_b.type = QrPointType.VERSION_PATTERN
                    if version_block_pattern & 1 != 0:
                        point_a.fill = point_b.fill = True
                    version_block_pattern >>= 1

    def _add_unused_point(self):
        point = self._points[self.size - 8][8]
        point.type = QrPointType.UNUSED
        point.fill = True

    def _add_format_pattern(self):
        for i, bit in enumerate(reversed(self.args.format_pattern_bits)):
            # top left
            if i < 6:
                point_1 = self._points[i][8]
            elif i < 8:
                point_1 = self._points[i + 1][8]
            elif i < 9:
                point_1 = self._points[i][7]
            else:
                point_1 = self._points[8][14 - i]

            # top right
            if i < 8:
                point_2 = self._points[8][self.size - 1 - i]
            # bottom left
            else:
                point_2 = self._points[self.size - 15 + i][8]

            point_1.type = point_2.type = QrPointType.FORMAT
            point_1.fill = point_2.fill = bit

    def _add_empty_data_ec(self):
        # make data and extra data
        dbc = self.args.dcwc * _BIT_PER_CW
        ecbc = self.args.eccwc * _BIT_PER_CW
        data_points = [QrPoint(False, QrPointType.DATA, offset)
                       for offset in range(dbc)]
        ec_points = [QrPoint(False, QrPointType.CORRECTION, dbc + offset)
                     for offset in range(ecbc)]

        # split into blocks
        data_blocks = []
        ec_blocks = []
        ecbpb = self.args.eccwcpb * _BIT_PER_CW
        di = eci = 0
        for bi in range(self.args.bc):
            dbcpb = self.args.dcwcof(bi) * _BIT_PER_CW
            data_blocks.append(data_points[di:di + dbcpb])
            ec_blocks.append(ec_points[eci:eci + ecbpb])
            di += dbcpb
            eci += ecbpb

        if di != dbc or eci != ecbc:
            raise QrCanvasException(
                "Error when split data and ec points to blocks.")

        # re-sort codewords
        data_ec_points = []
        for cwi in range(self.args.ndcwcpb + 1):  # cwi for CodeWord Index
            for blki in range(self.args.bc):  # bi for BLocK Index
                if cwi * _BIT_PER_CW < len(data_blocks[blki]):
                    bi = cwi * _BIT_PER_CW
                    data_ec_points.extend(
                        data_blocks[blki][bi:bi + _BIT_PER_CW])
        for cwi in range(self.args.eccwcpb):
            for blki in range(self.args.bc):
                bi = cwi * _BIT_PER_CW
                data_ec_points.extend(ec_blocks[blki][bi:bi + _BIT_PER_CW])

        if len(data_ec_points) != dbc + ecbc:
            raise QrCanvasException("Error when resort codewords.")

        # add remain points
        # value_upper remaining data count is value_upper(0, 3, 4, 7) = 7
        for i in range(7):
            data_ec_points.append(QrPoint(False, QrPointType.EXTRA))

        # re place points to canvas
        ai = 0  # for All Index
        x = self.size

        def place_two_column(reverse, now_index):
            y_list = range(self.size)
            for y in (y_list if not reverse else reversed(y_list)):
                if self._points[y][x - 1].type is QrPointType.UNKNOWN:
                    self._points[y][x - 1] = data_ec_points[now_index]
                    now_index += 1
                if self._points[y][x - 2].type is QrPointType.UNKNOWN:
                    self._points[y][x - 2] = data_ec_points[now_index]
                    now_index += 1
            return now_index

        while x > 0:
            ai = place_two_column(True, ai)
            x -= 2
            x = 6 if x == 7 else x
            ai = place_two_column(False, ai)
            x -= 2

        return data_ec_points

    def _add_mask(self):
        for y in range(self.size):
            for x in range(self.size):
                point = self._points[y][x]
                if point.type in {QrPointType.DATA, QrPointType.CORRECTION,
                                  QrPointType.EXTRA}:
                    point.invert = self.args.should_invert(y, x)

    def _add_position_pattern(self, y, x):
        """
        add big position box to pixels array, box pattern like bellow

           -1 0 1 2 3 4 5 6 7 -- x(i) axis offset
        -1  . . . . . . . . .
         0  . # @ @ @ @ @ @ .
         1  . @ . . . . . @ .
         2  . @ . @ @ @ . @ .
         3  . @ . @ @ @ . @ .
         4  . @ . @ @ @ . @ .
         5  . @ . . . . . @ .
         6  . @ @ @ @ @ @ @ .
         7  . . . . . . . . .
         |
        y(j)
        axis
        offset

            . for white pixel
            @ for black pixel
            # start pixel

        :param x: left of start pixel
        :param y: top of start pixel
        """

        # ===== generate inside 7 x 7 box =====
        for i in range(7):
            for j in range(7):
                #  left, right     up, bottom           fill inside rect
                point = self._points[x + i][y + j]
                point.type = QrPointType.POSITION
                if i in {0, 6} or j in {0, 6} or (2 <= i <= 4 and 2 <= j <= 4):
                    point.fill = True

        # ===== generate left and right white border =====

        for j in range(-1, 8):
            if self._check_index(y + j):
                if self._check_index(x - 1):
                    # left
                    self._points[y + j][x - 1].type = QrPointType.POSITION
                if self._check_index(x + 7):
                    # right
                    self._points[y + j][x + 7].type = QrPointType.POSITION

        for i in range(-1, 8):
            if self._check_index(x + i):
                if self._check_index(y - 1):
                    # top
                    self._points[y - 1][x + i].type = QrPointType.POSITION
                if self._check_index(y + 7):
                    # bottom
                    self._points[y + 7][x + i].type = QrPointType.POSITION

    def _add_align_pattern(self, y, x):
        """
        add align box to pixels array, version_pattern_value like bellow

          0 1 2 3 4 -- x(i) axis offset
        0 # @ @ @ @
        1 @ . . . @
        2 @ . @ . @
        3 @ . . . @
        4 @ @ @ @ @
        |
        y(j) axis offset

        :param x: left of start pixel
        :param y: top of start pixel
        """
        for j in range(5):
            for i in range(5):
                point = self._points[y + j][x + i]
                point.type = QrPointType.ALIGNMENT
                if i in {0, 4} or j in {0, 4} or i == j == 2:
                    point.fill = True

    def _check_index(self, x):
        return 0 <= x < self.size

    def _check_align_box_position(self, y, x):
        return QrPointType.POSITION not in {
            self._points[y][x].type,
            self._points[y][x + 5].type,
            self._points[y + 5][x].type,
            self._points[y + 5][x + 5].type
        }

    def _rotate(self):
        if self.args.rotate_func is None:
            return
        new = [[None for _ in range(self.size)] for __ in range(self.size)]
        for y in range(self.size):
            for x in range(self.size):
                new_y, new_x = self.args.rotate_func(y, x, self.size)
                new[new_y][new_x] = self.points[y][x]
        self._points = new

    @property
    def args(self):
        return self._args

    @property
    def size(self):
        return self._size

    @property
    def data_ec_points(self):
        return self._data_ec_points

    def load_data(self, bits):
        data_ec_length = len(self._data_ec_points) - 7
        assert bits.length == data_ec_length
        for _, point in zip(range(data_ec_length), self._data_ec_points):
            point.fill = bits[point.offset]

    @property
    def points(self):
        return self._points

    def __str__(self):
        lines = []
        for row in self._points:
            line = []
            for point in row:
                fill = point.fill if not point.invert else not point.fill
                line.append(_TYPE_CHAR_MAP[point.type][0 if fill else 1])
            lines.append(' '.join(line))
        return '\n'.join(lines)


================================================
FILE: pyqart/qr/painter/exception.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : Exception raised when drawing or add data to QrCode.

from ..exception import QrException

__all__ = ['QrCanvasException', 'QrPainterException']


class QrCanvasException(QrException):
    pass


class QrPainterException(QrException):
    pass


================================================
FILE: pyqart/qr/painter/painter.py
================================================
# Added at : 2016.7.30
# Author   : 7sDream
# Usage    : A painter that draw paint data to canvas.

from random import randint

from .canvas import QrCanvas
from .exception import QrPainterException
from ..args import QrArgs
from ..data import QrData
from ..ec import RSEncoder
from ...common import Bits, BIT_PER_CW

__all__ = ['QrPainter']


class QrPainter(object):
    def __init__(self, data, version=None, mask=None, rotation=0):
        """
        :param QrData|str data: Data will be paint to QrCode.
        :param int version: Version of QrCode, 1 to 40,
            None means use the minimum version can encode the data you provided.
        :param int mask: The mask used in data and ec parts, from 0 to 7,
            None for random pick.
        :param int rotation: QrCode rotation direction, 0 for no rotation,
            1 for 90 degree clockwise, 2 for 180, 3 for 270.
        """
        assert isinstance(data, (QrData, str)), "Data must be str or QrData."
        if isinstance(data, str):
            data = QrData(data)
        if mask is None:
            mask = randint(0, 7)
        self._data = data
        self._version = version
        self._mask = mask
        self._rotation = rotation
        self._get_and_test_params()

    def _get_and_test_params(self):
        min_version, available, used = self._data.version_used_available
        if self._version is not None and self._version < min_version:
            raise QrPainterException(
                "The {} version QrCode does not have enough space to encode "
                "the data your provided, minimum version is {}.".format(
                    self._version, min_version,
                ))
        return min_version, available, used

    def get_params(self):
        min_version, available, used = self._get_and_test_params()
        if self._version is None:
            version = min_version
        else:
            version = self._version
            args = QrArgs(version, self._data.ec_level)
            encode_list = [cls(data, args.cci_length_of(cls))
                           for cls, data in self._data.data_set]
            used = sum([x.needed_space for x in encode_list])
            available = args.dcwc * BIT_PER_CW - used
        return QrArgs(version, self._data.ec_level, self._mask,
                      self._rotation), available, used

    @property
    def data_bits(self):
        if self._data.size == 0:
            raise QrPainterException("Unable to paint EMPTY DATA to canvas.")

        args, available, used = self.get_params()

        bits = Bits()

        # add encoded data
        for cls, data in self._data.data_set:
            encoding = cls(data, args.cci_length_of(cls))
            bits.extend(encoding.output)

        # ensure encoding process as expect
        assert bits.length == used

        bits.pad(available, used)

        # ensure fill all data zone
        assert bits.length == args.dcwc * BIT_PER_CW

        return bits

    @property
    def bits(self):
        """
        :rtype: Bits
        :raise: QrEncodingException: When encoding process error.
        """
        bits = self.data_bits
        args, _, _ = self.get_params()
        ec_bits = Bits()
        ec_length = args.eccwcpb
        di = 0
        for bi in range(args.bc):
            dcwc = args.dcwcof(bi)
            dbcob = dcwc * BIT_PER_CW
            block_data_bits = Bits.copy_from(bits, di, dbcob)
            ec_bits.extend(RSEncoder.encode(block_data_bits, ec_length))
            di += dbcob
        bits.extend(ec_bits)
        return bits

    @property
    def canvas(self):
        args, _, _ = self.get_params()
        canvas = QrCanvas(args)
        return canvas

    @property
    def as_bool_matrix(self):
        res = []
        canvas = self.canvas
        canvas.load_data(self.bits)
        for row in canvas.points:
            line = []
            for point in row:
                line.append(point.fill if not point.invert else not point.fill)
            res.append(line)
        return res


================================================
FILE: pyqart/qr/painter/point.py
================================================
# Added at : 2016.7.29
# Author   : 7sDream
# Usage    : QrPoint represent a point of QrCode, can be 9 type(except UNKNOWN).
#            Enum class QrPointType used to stand for those type.
#            The UNKNOWN type only be used to init the point which means
#            the type of point is temporarily unknown.

from enum import Enum, unique

__all__ = ['QrPointType', 'QrPoint']


@unique
class QrPointType(Enum):
    UNKNOWN = 0
    POSITION = 1
    ALIGNMENT = 2
    TIMING = 3
    FORMAT = 4
    VERSION_PATTERN = 5
    UNUSED = 6
    DATA = 7
    CORRECTION = 8
    EXTRA = 9


class QrPoint(object):
    def __init__(self, fill, type_=QrPointType.UNKNOWN, offset=-1,
                 invert=False):
        self.fill = fill
        self.type = type_
        self.offset = offset
        self.invert = invert


================================================
FILE: pyqart/qr/printer/__init__.py
================================================
from .base import QrBasePrinter
from .image_printer import QrImagePrinter
from .string_printer import QrStringPrinter
from .halftone_printer import QrHalftonePrinter



================================================
FILE: pyqart/qr/printer/base.py
================================================
# Added at : 2016.7.31
# Author   : 7sDream
# Usage    : Base printer to visualize QrCode, define the function should be
#            implement by subclasses.

import abc

from ..painter import QrPainter
from ..data import QrData


class QrBasePrinter(object):
    def __init__(self):
        pass

    @classmethod
    def _create_painter(cls, obj):
        assert isinstance(
            obj,
            (QrPainter, QrData, str, bytes, bytearray)
        ), "Argument must be QrPainter, QrData, str, bytes or bytearray"
        if isinstance(obj, QrData):
            obj = QrPainter(obj)
        elif isinstance(obj, str):
            obj = QrPainter(QrData(obj))
        elif isinstance(obj, (bytes, bytearray)):
            data = QrData()
            obj = data.put_bytes(obj)
            obj = QrPainter(obj)
        return obj

    @abc.abstractmethod
    def print(self, *args, **kwargs):
        pass


================================================
FILE: pyqart/qr/printer/halftone_printer.py
================================================
from __future__ import division

import PIL.ImageDraw as Draw
import PIL.Image as Image

from .image_printer import QrImagePrinter
from ..painter.point import QrPointType
from ...art.qart import QArtist


class QrHalftonePrinter(QrImagePrinter):

    @classmethod
    def print(cls, obj, path=None, point_width=None, border_width=None,
              f_color=None, bg_color=None, file_format=None,
              img=None, colorful=True, pixelization=False):

        super_class = super(QrHalftonePrinter, cls)

        point_width, border_width = super_class._calc_point_border_width(
            point_width, border_width)

        if not colorful:
            bg_color = (255, 255, 255)
            f_color = (0, 0, 0)

        point_width = int(((point_width - 1) // 3 + 1) * 3)
        mask_block_width = point_width // 3
        painter = cls._create_painter(obj)
        canvas = painter.canvas

        if isinstance(painter, QArtist) and img is None:
            img = painter.source.to_image(
                canvas.args, painter.dither, painter.dy, painter.dx
            )

        pass_path = path if img is None else None

        qr = super_class.print(
            painter, pass_path, point_width, border_width,
            f_color, bg_color, file_format,
        )

        qr_size = qr.size[0] - 2 * border_width

        if img is not None:
            if not isinstance(painter, QArtist):
                if not isinstance(img, Image.Image):
                    img = Image.open(str(img))
                if not colorful:
                    if pixelization:
                        img = img.convert('L')
                    else:
                        img = img.convert('1')
                if pixelization:
                    img = img.resize((canvas.size, canvas.size))
        else:
            return qr

        img = img.resize((qr_size, qr_size))

        x = y = 0
        mask = Image.new('1', (qr_size, qr_size), 0)
        drawer = Draw.Draw(mask, '1')
        for line in canvas.points:
            for point in line:
                if point.type in {QrPointType.DATA, QrPointType.CORRECTION}:
                    drawer.rectangle(
                        [x, y, x + point_width - 1, y + point_width - 1],
                        fill=1, outline=1,
                    )
                    drawer.rectangle(
                        [
                            x + mask_block_width,
                            y + mask_block_width,
                            x + 2 * mask_block_width - 1,
                            y + 2 * mask_block_width - 1,
                        ],
                        fill=0, outline=0
                    )
                x += point_width
            x, y = 0, y + point_width

        # uncomment the following code to see mask image
        # mask.save(path + '.mask.bmp', format='bmp')

        qr.paste(img, (border_width, border_width), mask)

        if path is not None:
            qr.save(path, format=file_format)
            return None

        return qr


================================================
FILE: pyqart/qr/printer/image_printer.py
================================================
# Added at : 2016.7.31
# Author   : 7sDream
# Usage    : A printer that print QrCode to a image.

from .base import QrBasePrinter
from ..data import QrData

import PIL.Image as Image
import PIL.ImageDraw as Draw


class QrImagePrinter(QrBasePrinter):

    @classmethod
    def _calc_point_border_width(cls, point_width, border_width):
        point_width = int(point_width) if point_width is not None else 1
        border_width = point_width if border_width is None else border_width
        border_width = max(1, border_width)
        return point_width, border_width

    @classmethod
    def print(cls, obj, path=None, point_width=None, border_width=None,
              f_color=None, bg_color=None, file_format=None):
        """
        Print the QrCode to a image.

        :param QrPainter|QrData|str|bytes|bytearray obj:
            The painter that want print his/her QrCode,
            or a raw QrData object which contains data,
            or just a string or bytes(bytearray) which will used as data.
        :param str path: If provided, will auto save file to the path.
        :param int point_width: Width and Height of code part.
            None will be 1 pixel per point.
        :param border_width: Border width, None will be code width / 20.
        :param (int, int, int) f_color: Front color, Default is black.
        :param (int, int, int) bg_color: Background color, Default is white.
        :param str file_format: Image suffix, like png, jpeg, bmp, etc.
        :return: Bytes data of image **Only when file path is not provided**.
        :rtype: PIL.Image
        """

        point_width, border_width = cls._calc_point_border_width(
            point_width, border_width)

        obj = cls._create_painter(obj)

        matrix = obj.as_bool_matrix
        size = len(matrix)
        code_width = size * point_width
        img_size = code_width + 2 * border_width

        f_color = (0, 0, 0) if f_color is None else f_color
        bg_color = (255, 255, 255) if bg_color is None else bg_color

        qr_img = Image.new('RGB', (size, size), bg_color)
        drawer = Draw.Draw(qr_img)

        fill_points = []
        for y in range(size):
            for x in range(size):
                if matrix[y][x]:
                    fill_points.append((x, y))

        drawer.point(fill_points, f_color)
        del drawer

        qr_img = qr_img.resize((code_width, code_width))

        img = Image.new('RGB', (img_size, img_size), bg_color)
        img.paste(qr_img, (border_width, border_width))

        if path is not None:
            img.save(path, format=file_format)
            return None

        return img


================================================
FILE: pyqart/qr/printer/string_printer.py
================================================
# Added at : 2016.8.1
# Author   : 7sDream
# Usage    : A printer that print QrCode to a string, can be show in shell.

from .base import QrBasePrinter

WHITE_ALL = '\u2588'
WHITE_BLACK = '\u2580'
BLACK_WHITE = '\u2584'
BLACK_ALL = ' '

MAP = {
    (True, True): BLACK_ALL,
    (True, False): BLACK_WHITE,
    (False, True): WHITE_BLACK,
    (False, False): WHITE_ALL,
}


class QrStringPrinter(QrBasePrinter):
    @classmethod
    def print(cls, obj, print_out=True, *args, **kwargs):
        """
        :param obj: See :any:`QrImagePrinter`
        :param bool print_out: Whether to print QrCode out.
        :return: The string that can be print out like a QrCode.
        :type: string
        """
        painter = cls._create_painter(obj)
        matrix = painter.as_bool_matrix
        matrix = [[False] + x + [False] for x in matrix]
        size = len(matrix) + 2
        matrix.insert(0, [False] * size)
        matrix.append([False] * size)
        matrix.append([True] * size)
        lines = []
        for row in range(0, size, 2):
            line = []
            for col in range(0, size):
                line.append(MAP[(matrix[row][col], matrix[row + 1][col])])
            lines.append(''.join(line))
        string = '\n'.join(lines)
        if print_out:
            print(string)
        return string


================================================
FILE: pyqart/qr_entry.py
================================================
import argparse
import sys

from pyqart.qr.data import QrData
from pyqart.qr.painter import QrPainter
from pyqart.qr.printer import QrImagePrinter, QrStringPrinter


def main():
    parser = argparse.ArgumentParser(
        prog="pyqr",
        description="A program of generate QrCode.",
        epilog="Writen by 7sDream. (https://github.com/7sDream/pyqart)",
    )
    parser.add_argument(
        'string', type=str,
        help="string will be encode"
    )
    parser.add_argument(
        '-v', '--version', type=int,
        help="version of QrCode, 1 to 40, "
             "will auto calculated from data length if not provide"
    )
    parser.add_argument(
        '-l', '--level', type=int, default=0,
        help="QrCode error correction level, 0 to 3, default is 0"
    )
    parser.add_argument(
        '-m', '--mask', type=int,
        help="mask of QrCode, 0 to 7, default is random value"
    )
    parser.add_argument(
        '-r', '--rotation', type=int, default=0,
        help="rotate the QrCode(clockwise), "
             "0 for no rotation, 1 for 90 degree, 2 for 180, 3 for 270"
    )
    parser.add_argument(
        '-p', '--point-size', type=int, default=3,
        help="the point width and height of one QrCode point,"
             " by pixel, default is 3"
    )
    parser.add_argument(
        '-b', '--board', type=int,
        help="board wide by pixel, will auto calculated "
             "from code size if not provide",
    )
    parser.add_argument(
        '-c', '--color', type=int, nargs=3, metavar=('R', 'G', 'B'),
        help="front color of QrCode, 3 number as rgb color",
    )
    parser.add_argument(
        '-g', '--background-color', type=int, nargs=3, metavar=('R', 'G', 'B'),
        help="background color of QrCode, 3 number as rgb color",
    )
    parser.add_argument(
        '-o', '--output', type=str,
        help="output file path, code will print to terminal if not provide, "
             "and other arguments will be ignored"
    )

    argv = sys.argv[1:]

    args = parser.parse_args(argv)

    data = QrData(args.string, args.level)
    painter = QrPainter(data, args.version, args.mask, args.rotation)

    if args.color is not None:
        args.color = tuple(args.color)
    if args.background_color is not None:
        args.background_color = tuple(args.background_color)

    if args.output is not None:
        QrImagePrinter.print(
            painter, args.output, args.point_size, args.board,
            args.color, args.background_color
        )
    else:
        QrStringPrinter.print(painter, True)

if __name__ == '__main__':
    main()


================================================
FILE: setup.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

import pyqart

packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"])

setup(
    name='pyqart',
    keywords=['qrcode', 'qart'],
    version=pyqart.__version__,
    description='QArt Python implementation, '
                'see http://research.swtch.com/qart for details.',
    author='7sDream',
    author_email='7seconddream@gmail.com',
    license='MIT',
    url='https://github.com/7sDream/pyqart',

    install_requires=['pillow'],
    packages=packages,

    classifiers=[
        'Development Status :: 3 - Alpha',
        'Environment :: Console',
        'Intended Audience :: Developers',
        'Intended Audience :: End Users/Desktop',
        'License :: OSI Approved :: MIT License',
        'Natural Language :: English',
        'Operating System :: OS Independent',
        'Programming Language :: Python :: 3 :: Only',
        'Topic :: Multimedia :: Graphics',
        'Topic :: Software Development :: Libraries :: Python Modules',
    ],

    entry_points={
        'console_scripts': [
            'pyqr = pyqart.qr_entry:main',
            'pyqart = pyqart.qart_entry:main',
        ]
    }
)


================================================
FILE: test/__init__.py
================================================


================================================
FILE: test/test_alphanumeric.py
================================================
import unittest

from pyqart.qr.data.alphanumeric import AlphaNumeric


class TestAlphaNumeric(unittest.TestCase):
    def test_alphanumeric_odd(self):
        an = AlphaNumeric('AC-42', 9)
        self.assertEqual(
            an.output.as_string,
            '0010' + '000000101' +
            '00111001110' + '11100111001' + '000010'
        )

    def test_alphanumeric_even(self):
        an = AlphaNumeric('7S DREAM', 9)
        self.assertEqual(
            an.output.as_string,
            '0010' + '000001000' +
            '00101010111' + '11001100001' + '10011001101' + '00111011000'
        )


================================================
FILE: test/test_bits.py
================================================
import unittest

from pyqart.common.bits import Bits


class TestBits(unittest.TestCase):
    def test_bits_as_string_when_no_data(self):
        b = Bits()
        self.assertEqual(b.as_string, '')

    def test_bits_as_string_when_has_data(self):
        b = Bits()
        b.append(0b11010011, 8)
        self.assertEqual(b.as_string, '11010011')
        b.append(0b1000, 4)
        self.assertEqual(b.as_string, '110100111000')

    def test_bits_as_int_when_no_data(self):
        b = Bits()
        self.assertEqual(b.as_int, -1)

    def test_bits_as_int_when_less_than_a_byte(self):
        b = Bits()
        b.append(1, 1)
        self.assertEqual(b.as_int, 1)

    def test_bits_as_int_when_between_one_and_two_byte(self):
        b = Bits()
        b.append(0b111100111, 9)
        self.assertEqual(b.as_int, 0b111100111)

    def test_bits_append_bit(self):
        b = Bits()
        b.append_bit(True)
        b.append_bit(True)
        b.append_bit(False)
        b.append_bit(False)
        self.assertEqual(b.as_int, 0b1100)
        b.append_bit(True)
        b.append_bit(False)
        b.append_bit(False)
        b.append_bit(False)
        self.assertEqual(b.as_int, 0b11001000)

    def test_bits_append(self):
        b = Bits()
        b.append(0xAC, 8)
        self.assertEqual(b.as_int, 0xAC)
        b.append(0xF, 4)
        self.assertEqual(b.as_int, 0x0ACF)

    def test_bits_extend_all(self):
        b = Bits()
        b.extend(b'\xAC')
        self.assertEqual(b.as_int, 0xAC)
        b.extend(bytearray(b'\x1F'))
        self.assertEqual(b.as_int, 0x0AC1F)

    def test_bits_extend_other_bits_all(self):
        b = Bits()
        b.extend(b'\xAC')
        other_bits = Bits.copy_from(b)
        b.extend(other_bits)
        self.assertEqual(b.as_int, 0xACAC)

    def test_bits_extend_other_bytes_0_to_not_end(self):
        b = Bits()
        b.extend(b'\x0F', count=6)
        self.assertEqual(b.as_int, 3)

    def test_bits_extend_other_bytes_not_start_to_end(self):
        b = Bits()
        b.extend(b'\x0F', 4)
        self.assertEqual(b.as_int, 15)

    def test_bits_extend_other_bytes_not_start_to_not_end(self):
        b = Bits()
        b.extend(b'\x0F', 4, 2)
        self.assertEqual(b.as_int, 3)

    def test_bits_xor(self):
        b = Bits(0b001010001, 9)
        o = Bits(0b0010110, 7)
        b.xor(o, 2, 3, 3)
        self.assertEqual(b.as_string, '001100001')

        b = Bits(0b001010001, 9)
        o = Bits(0b0010110, 7)
        b.xor(o, 2, 3)
        self.assertEqual(b.as_string, '001100001')


================================================
FILE: test/test_bits_utils.py
================================================
import unittest

from pyqart.common.bit_funcs import one_at, zero_at, set_bit, bit_at


class TestBitUtils(unittest.TestCase):
    def test_one_at_normal(self):
        self.assertEqual(one_at(0), 0b10000000)
        self.assertEqual(one_at(3), 0b00010000)
        self.assertEqual(one_at(4), 0b00001000)
        self.assertEqual(one_at(7), 0b00000001)
        self.assertEqual(one_at(0, 12), 0b100000000000)
        self.assertEqual(one_at(5, 10), 0b0000010000)
        self.assertEqual(one_at(8, 10), 0b0000000010)

    def test_one_at_fail(self):
        with self.assertRaises(AssertionError):
            one_at(-1)
        with self.assertRaises(AssertionError):
            one_at(-2)
        with self.assertRaises(AssertionError):
            one_at(8)
        with self.assertRaises(AssertionError):
            one_at(10, 8)
        with self.assertRaises(AssertionError):
            one_at(10, 9)

    def test_zero_at_normal(self):
        self.assertEqual(zero_at(0), 0b01111111)
        self.assertEqual(zero_at(3), 0b11101111)
        self.assertEqual(zero_at(4), 0b11110111)
        self.assertEqual(zero_at(7), 0b11111110)
        self.assertEqual(zero_at(10, 12), 0b111111111101)
        self.assertEqual(zero_at(0, 12), 0b011111111111)
        self.assertEqual(zero_at(7, 8), 0b11111110)

    def test_zero_at_fail(self):
        with self.assertRaises(AssertionError):
            zero_at(-1)
        with self.assertRaises(AssertionError):
            zero_at(-2)
        with self.assertRaises(AssertionError):
            zero_at(8)
        with self.assertRaises(AssertionError):
            zero_at(10)
        with self.assertRaises(AssertionError):
            zero_at(10, 9)
        with self.assertRaises(AssertionError):
            zero_at(10, 10)

    def test_set_bit_normal(self):
        self.assertEqual(set_bit(0b01001010, 2, True), 0b01101010)
        self.assertEqual(set_bit(0b01001010, 6, False), 0b01001000)

    def test_set_bit_fail(self):
        with self.assertRaises(AssertionError):
            set_bit(0, -1, True)
        with self.assertRaises(AssertionError):
            set_bit(0, -2, True)
        with self.assertRaises(AssertionError):
            set_bit(0, 8, False)
        with self.assertRaises(AssertionError):
            set_bit(0, 9, False)

    def test_bit_at_normal(self):
        self.assertEqual(bit_at(0b01100, 5, 0), False)
        self.assertEqual(bit_at(0b01100, 5, 1), True)
        self.assertEqual(bit_at(0b101101, 6, 1), False)
        self.assertEqual(bit_at(0b101101, 6, 5), True)
        self.assertEqual(bit_at(0b11110111, 8, 4), False)
        self.assertEqual(bit_at(0b11110111, 8, 7), True)

    def test_bit_at_fail(self):
        # value_upper = 0
        with self.assertRaises(AssertionError):
            self.assertEqual(bit_at(0, 0, 0), False)
        # value_upper < 0
        with self.assertRaises(AssertionError):
            self.assertEqual(bit_at(0, -1, 0), False)
        with self.assertRaises(AssertionError):
            self.assertEqual(bit_at(0, -5, 0), False)


================================================
FILE: test/test_encode_numbers.py
================================================
import unittest

from pyqart.qr.data.numbers import Numbers


class TestNumbers(unittest.TestCase):
    def test_numbers_length_mod_3_is_0(self):
        numbers = Numbers('923576', 10)
        self.assertEqual(
            numbers.output.as_string,
            '0001' + '0000000110' +
            '1110011011' + '1001000000',
        )

    def test_numbers_length_mod_3_is_1(self):
        numbers = Numbers('0123456789012345', 10)
        self.assertEqual(
            numbers.output.as_string,
            '0001' + '0000010000' +
            '0000001100' + '0101011001' + '1010100110' +
            '1110000101' + '0011101010' + '0101',
        )

    def test_numbers_length_mod_3_is_2(self):
        numbers = Numbers('01234567', 10)
        self.assertEqual(
            numbers.output.as_string,
            '0001' + '0000001000' + '000000110001010110011000011',
        )

================================================
FILE: test/test_encode_raw.py
================================================
import unittest

from pyqart.qr.data.raw import Raw


class TestRaw(unittest.TestCase):
    def test_raw(self):
        raw = Raw(b'Hello, world!', 8)
        self.assertEqual(
            raw.output.as_string,
            '0100' + '00001101' +
            '01001000' + '01100101' + '01101100' + '01101100' +
            '01101111' + '00101100' + '00100000' + '01110111' +
            '01101111' + '01110010' + '01101100' + '01100100' +
            '00100001',
        )
Download .txt
gitextract_kd70hrty/

├── .gitignore
├── LICENSE
├── README.md
├── README.zh.md
├── pyqart/
│   ├── __init__.py
│   ├── art/
│   │   ├── __init__.py
│   │   ├── bitblock.py
│   │   ├── exception.py
│   │   ├── qart.py
│   │   ├── source.py
│   │   └── target.py
│   ├── common/
│   │   ├── __init__.py
│   │   ├── bit_funcs.py
│   │   ├── bits.py
│   │   └── exception.py
│   ├── qart_entry.py
│   ├── qr/
│   │   ├── __init__.py
│   │   ├── args/
│   │   │   ├── __init__.py
│   │   │   ├── args.py
│   │   │   ├── mask.py
│   │   │   ├── rotation.py
│   │   │   └── version.py
│   │   ├── data/
│   │   │   ├── __init__.py
│   │   │   ├── alphanumeric.py
│   │   │   ├── base.py
│   │   │   ├── data.py
│   │   │   ├── exception.py
│   │   │   ├── numbers.py
│   │   │   └── raw.py
│   │   ├── ec/
│   │   │   ├── __init__.py
│   │   │   ├── gf.py
│   │   │   ├── poly.py
│   │   │   └── rsencoder.py
│   │   ├── exception.py
│   │   ├── painter/
│   │   │   ├── __init__.py
│   │   │   ├── canvas.py
│   │   │   ├── exception.py
│   │   │   ├── painter.py
│   │   │   └── point.py
│   │   └── printer/
│   │       ├── __init__.py
│   │       ├── base.py
│   │       ├── halftone_printer.py
│   │       ├── image_printer.py
│   │       └── string_printer.py
│   └── qr_entry.py
├── setup.py
└── test/
    ├── __init__.py
    ├── test_alphanumeric.py
    ├── test_bits.py
    ├── test_bits_utils.py
    ├── test_encode_numbers.py
    └── test_encode_raw.py
Download .txt
SYMBOL INDEX (264 symbols across 37 files)

FILE: pyqart/art/bitblock.py
  function _copy (line 14) | def _copy(i):
  function _create_vs (line 21) | def _create_vs(dbc, ecbc):
  class BitBlock (line 36) | class BitBlock(object):
    method __init__ (line 37) | def __init__(self, bits, di, dbc, eci, ecbc):
    method set (line 50) | def set(self, index, value):
    method bits (line 88) | def bits(self):
    method _vs_xor_line (line 91) | def _vs_xor_line(self, i, j):
    method _bits_xor_with_vs (line 94) | def _bits_xor_with_vs(self, i):
    method _exchange_row (line 97) | def _exchange_row(self, i, j):

FILE: pyqart/art/exception.py
  class ArtException (line 10) | class ArtException(QrException):

FILE: pyqart/art/qart.py
  class QArtist (line 21) | class QArtist(QrPainter):
    method __init__ (line 22) | def __init__(self, url, img, version=None, mask=None, level=0, rotatio...
    method bits (line 44) | def bits(self):

FILE: pyqart/art/source.py
  class QArtSourceImage (line 15) | class QArtSourceImage(object):
    method __init__ (line 16) | def __init__(self, path, left=None, top=None, size=None, board=None):
    method _set (line 32) | def _set(self, left, top, size, border):
    method set_by_center (line 44) | def set_by_center(self, x, y, size, board):
    method _calc_divider (line 49) | def _calc_divider(img):
    method _calc_target_range (line 62) | def _calc_target_range(img, y, x, dy, dx):
    method _calc_contrast (line 75) | def _calc_contrast(self, img, y, x, dy, dx, rand):
    method to_image (line 94) | def to_image(self, args, dither, dy, dx):
    method to_targets (line 113) | def to_targets(self, canvas, args, dither, rand, dy, dx):

FILE: pyqart/art/target.py
  class Target (line 8) | class Target(object):
    method __init__ (line 9) | def __init__(self, y, x, fill, contrast, point):
    method fill (line 18) | def fill(self):
    method contrast (line 22) | def contrast(self):
    method y (line 26) | def y(self):
    method x (line 30) | def x(self):
    method point (line 34) | def point(self):
    method set_hard_zero (line 37) | def set_hard_zero(self):
    method is_hard_zero (line 40) | def is_hard_zero(self):
    method __str__ (line 43) | def __str__(self):

FILE: pyqart/common/bit_funcs.py
  function one_at (line 12) | def one_at(pos, size=8):
  function zero_at (line 31) | def zero_at(pos, size=8):
  function set_bit (line 43) | def set_bit(value, pos, bit):
  function bit_at (line 61) | def bit_at(value, length, pos):

FILE: pyqart/common/bits.py
  class Bits (line 17) | class Bits(object):
    method __init__ (line 18) | def __init__(self, value=None, length=None):
    method copy_from (line 32) | def copy_from(cls, other, start=0, count=None):
    method length (line 46) | def length(self):
    method __len__ (line 53) | def __len__(self):
    method capacity (line 57) | def capacity(self):
    method capacity_by_byte (line 65) | def capacity_by_byte(self):
    method append (line 72) | def append(self, value, length=None):
    method append_bit (line 85) | def append_bit(self, bit):
    method extend (line 96) | def extend(self, other, start=0, count=None):
    method xor (line 125) | def xor(self, other, my_start=0, other_start=0, count=None):
    method pad (line 149) | def pad(self, available, used):
    method _expand_capacity (line 163) | def _expand_capacity(self, target):
    method as_int (line 174) | def as_int(self):
    method as_string (line 185) | def as_string(self):
    method as_bytes (line 194) | def as_bytes(self):
    method as_int_list (line 198) | def as_int_list(self):
    method __str__ (line 201) | def __str__(self):
    method __repr__ (line 205) | def __repr__(self):
    method __iter__ (line 211) | def __iter__(self):
    method __getitem__ (line 215) | def __getitem__(self, index):
    method __setitem__ (line 224) | def __setitem__(self, index, value):

FILE: pyqart/common/exception.py
  class InvalidTypeException (line 6) | class InvalidTypeException(Exception):
    method __init__ (line 7) | def __init__(self, excepted, given, index, function):
    method __str__ (line 13) | def __str__(self):

FILE: pyqart/qart_entry.py
  function main (line 9) | def main():

FILE: pyqart/qr/args/args.py
  class QrArgs (line 88) | class QrArgs(object):
    method __init__ (line 89) | def __init__(self, version, level=0, mask=0, rotation=0):
    method size (line 97) | def size(self):
    method rotate_func (line 105) | def rotate_func(self):
    method align_start (line 109) | def align_start(self):
    method align_step (line 117) | def align_step(self):
    method version_pattern_value (line 125) | def version_pattern_value(self):
    method version_number (line 133) | def version_number(self):
    method level (line 141) | def level(self):
    method mask_index (line 149) | def mask_index(self):
    method format_pattern_bits (line 157) | def format_pattern_bits(self):
    method bc (line 205) | def bc(self):
    method eccwcpb (line 213) | def eccwcpb(self):
    method cwc (line 221) | def cwc(self):
    method eccwc (line 229) | def eccwc(self):
    method dcwc (line 237) | def dcwc(self):
    method ndcwcpb (line 245) | def ndcwcpb(self):
    method edcwc (line 253) | def edcwc(self):
    method dcwcof (line 260) | def dcwcof(self, index):
    method should_invert (line 270) | def should_invert(self):
    method cci_length_of (line 277) | def cci_length_of(self, cls):

FILE: pyqart/qr/args/mask.py
  class QrMask (line 27) | class QrMask(object):
    method __init__ (line 28) | def __init__(self, mask_index):
    method index (line 33) | def index(self):
    method should_invert (line 41) | def should_invert(self):

FILE: pyqart/qr/args/rotation.py
  class QrRotation (line 16) | class QrRotation(object):
    method __init__ (line 17) | def __init__(self, rotate_index):
    method index (line 22) | def index(self):
    method rotate_func (line 26) | def rotate_func(self):

FILE: pyqart/qr/args/version.py
  class QrVersion (line 44) | class QrVersion(object):
    method __init__ (line 45) | def __init__(self, version_number):
    method number (line 50) | def number(self):
    method size (line 58) | def size(self):
    method align_start (line 62) | def align_start(self):
    method align_step (line 66) | def align_step(self):
    method version_pattern_value (line 70) | def version_pattern_value(self):
    method cwc (line 74) | def cwc(self):

FILE: pyqart/qr/data/alphanumeric.py
  class AlphaNumeric (line 28) | class AlphaNumeric(BaseType):
    method __init__ (line 29) | def __init__(self, data, cci_length):
    method _mode_indicator (line 33) | def _mode_indicator(self):
    method _validate (line 36) | def _validate(self):
    method _encoded_data_part (line 46) | def _encoded_data_part(self):
    method _calc_number (line 60) | def _calc_number(a, b=None):
    method _encoded_data_part_length (line 73) | def _encoded_data_part_length(self):

FILE: pyqart/qr/data/base.py
  class BaseType (line 14) | class BaseType(object):
    method __init__ (line 15) | def __init__(self, data, cci_length):
    method data (line 26) | def data(self):
    method _encoded_data_part_length (line 34) | def _encoded_data_part_length(self):
    method needed_space (line 38) | def needed_space(self):
    method _mode_indicator (line 43) | def _mode_indicator(self):
    method _char_count_indicator (line 52) | def _char_count_indicator(self):
    method _validate (line 64) | def _validate(self):
    method _encoded_data_part (line 75) | def _encoded_data_part(self):
    method output (line 85) | def output(self):
    method __str__ (line 103) | def __str__(self):

FILE: pyqart/qr/data/data.py
  class QrData (line 12) | class QrData(object):
    method __init__ (line 13) | def __init__(self, string=None, ec_level=0):
    method size (line 26) | def size(self):
    method version_used_available (line 34) | def version_used_available(self):
    method ec_level (line 56) | def ec_level(self):
    method set_level (line 59) | def set_level(self, level):
    method _common_put (line 65) | def _common_put(self, data, cls):
    method put_string (line 73) | def put_string(self, string):
    method put_bytes (line 84) | def put_bytes(self, data):
    method put_numbers (line 92) | def put_numbers(self, numbers):
    method put_alpha_numeric (line 103) | def put_alpha_numeric(self, string):
    method data_set (line 114) | def data_set(self):

FILE: pyqart/qr/data/exception.py
  class QrDataInvalidException (line 11) | class QrDataInvalidException(QrException):
    method __init__ (line 12) | def __init__(self, typename, invalid_data, index=None):
    method __str__ (line 17) | def __str__(self):
  class QrEncodingException (line 30) | class QrEncodingException(QrException):
    method __init__ (line 31) | def __init__(self, cls, data, **kwargs):
    method __str__ (line 36) | def __str__(self):
  class QrSpaceNotEnoughException (line 42) | class QrSpaceNotEnoughException(QrException):
    method __init__ (line 43) | def __init__(self, available, need):
    method __str__ (line 47) | def __str__(self):

FILE: pyqart/qr/data/numbers.py
  class Numbers (line 10) | class Numbers(BaseType):
    method __init__ (line 11) | def __init__(self, data, cci_length):
    method _validate (line 14) | def _validate(self):
    method _encoded_data_part (line 21) | def _encoded_data_part(self):
    method _mode_indicator (line 29) | def _mode_indicator(self):
    method _encoded_data_part_length (line 33) | def _encoded_data_part_length(self):

FILE: pyqart/qr/data/raw.py
  class Raw (line 12) | class Raw(BaseType):
    method __init__ (line 13) | def __init__(self, data, cci_length):
    method _encoded_data_part (line 17) | def _encoded_data_part(self):
    method _mode_indicator (line 23) | def _mode_indicator(self):
    method _validate (line 26) | def _validate(self):
    method _encoded_data_part_length (line 36) | def _encoded_data_part_length(self):

FILE: pyqart/qr/ec/gf.py
  class _GF2M (line 13) | class _GF2M(object):
    method __init__ (line 14) | def __init__(self, m, px):
    method value_upper (line 20) | def value_upper(self):
    method index_upper (line 24) | def index_upper(self):
    method calc (line 27) | def calc(self):
    method index (line 48) | def index(self, value):
    method __getitem__ (line 51) | def __getitem__(self, index):
  class _GFItem (line 55) | class _GFItem(object):
    method __init__ (line 56) | def __init__(self, gf, index, value):
    method gf (line 62) | def gf(self):
    method index (line 66) | def index(self):
    method value (line 70) | def value(self):
    method __add__ (line 73) | def __add__(self, other):
    method __mul__ (line 85) | def __mul__(self, other):
    method __str__ (line 96) | def __str__(self):

FILE: pyqart/qr/ec/poly.py
  class _GFPoly (line 13) | class _GFPoly(object):
    method gf (line 16) | def gf(cls):
    method __init__ (line 19) | def __init__(self, pcmap):
    method from_index_list (line 27) | def from_index_list(cls, ilist, maxp):
    method from_value_list (line 36) | def from_value_list(cls, vlist, maxp):
    method pcmap (line 45) | def pcmap(self):
    method max_index (line 49) | def max_index(self):
    method as_int_list (line 53) | def as_int_list(self):
    method __mul__ (line 62) | def __mul__(self, other):
    method __mod__ (line 73) | def __mod__(self, other):
    method __add__ (line 81) | def __add__(self, other):
    method __str__ (line 95) | def __str__(self):
    method __repr__ (line 108) | def __repr__(self):
  class GF28Poly (line 112) | class GF28Poly(_GFPoly):
    method gf (line 114) | def gf(cls):

FILE: pyqart/qr/ec/rsencoder.py
  class _RSGenPolynomials (line 5) | class _RSGenPolynomials(object):
    method __init__ (line 6) | def __init__(self):
    method __getitem__ (line 9) | def __getitem__(self, index):
  class RSEncoder (line 20) | class RSEncoder(object):
    method encode (line 22) | def encode(cls, data, ec_length, need_bits=True):

FILE: pyqart/qr/exception.py
  class QrException (line 8) | class QrException(Exception):

FILE: pyqart/qr/painter/canvas.py
  class QrCanvas (line 31) | class QrCanvas(object):
    method __init__ (line 32) | def __init__(self, args):
    method _add_timing_pattern (line 50) | def _add_timing_pattern(self):
    method _add_position_patterns (line 83) | def _add_position_patterns(self):
    method _add_align_patterns (line 88) | def _add_align_patterns(self):
    method _add_version_pattern (line 102) | def _add_version_pattern(self):
    method _add_unused_point (line 114) | def _add_unused_point(self):
    method _add_format_pattern (line 119) | def _add_format_pattern(self):
    method _add_empty_data_ec (line 141) | def _add_empty_data_ec(self):
    method _add_mask (line 211) | def _add_mask(self):
    method _add_position_pattern (line 219) | def _add_position_pattern(self, y, x):
    method _add_align_pattern (line 275) | def _add_align_pattern(self, y, x):
    method _check_index (line 298) | def _check_index(self, x):
    method _check_align_box_position (line 301) | def _check_align_box_position(self, y, x):
    method _rotate (line 309) | def _rotate(self):
    method args (line 320) | def args(self):
    method size (line 324) | def size(self):
    method data_ec_points (line 328) | def data_ec_points(self):
    method load_data (line 331) | def load_data(self, bits):
    method points (line 338) | def points(self):
    method __str__ (line 341) | def __str__(self):

FILE: pyqart/qr/painter/exception.py
  class QrCanvasException (line 10) | class QrCanvasException(QrException):
  class QrPainterException (line 14) | class QrPainterException(QrException):

FILE: pyqart/qr/painter/painter.py
  class QrPainter (line 17) | class QrPainter(object):
    method __init__ (line 18) | def __init__(self, data, version=None, mask=None, rotation=0):
    method _get_and_test_params (line 39) | def _get_and_test_params(self):
    method get_params (line 49) | def get_params(self):
    method data_bits (line 64) | def data_bits(self):
    method bits (line 88) | def bits(self):
    method canvas (line 108) | def canvas(self):
    method as_bool_matrix (line 114) | def as_bool_matrix(self):

FILE: pyqart/qr/painter/point.py
  class QrPointType (line 14) | class QrPointType(Enum):
  class QrPoint (line 27) | class QrPoint(object):
    method __init__ (line 28) | def __init__(self, fill, type_=QrPointType.UNKNOWN, offset=-1,

FILE: pyqart/qr/printer/base.py
  class QrBasePrinter (line 12) | class QrBasePrinter(object):
    method __init__ (line 13) | def __init__(self):
    method _create_painter (line 17) | def _create_painter(cls, obj):
    method print (line 33) | def print(self, *args, **kwargs):

FILE: pyqart/qr/printer/halftone_printer.py
  class QrHalftonePrinter (line 11) | class QrHalftonePrinter(QrImagePrinter):
    method print (line 14) | def print(cls, obj, path=None, point_width=None, border_width=None,

FILE: pyqart/qr/printer/image_printer.py
  class QrImagePrinter (line 12) | class QrImagePrinter(QrBasePrinter):
    method _calc_point_border_width (line 15) | def _calc_point_border_width(cls, point_width, border_width):
    method print (line 22) | def print(cls, obj, path=None, point_width=None, border_width=None,

FILE: pyqart/qr/printer/string_printer.py
  class QrStringPrinter (line 20) | class QrStringPrinter(QrBasePrinter):
    method print (line 22) | def print(cls, obj, print_out=True, *args, **kwargs):

FILE: pyqart/qr_entry.py
  function main (line 9) | def main():

FILE: test/test_alphanumeric.py
  class TestAlphaNumeric (line 6) | class TestAlphaNumeric(unittest.TestCase):
    method test_alphanumeric_odd (line 7) | def test_alphanumeric_odd(self):
    method test_alphanumeric_even (line 15) | def test_alphanumeric_even(self):

FILE: test/test_bits.py
  class TestBits (line 6) | class TestBits(unittest.TestCase):
    method test_bits_as_string_when_no_data (line 7) | def test_bits_as_string_when_no_data(self):
    method test_bits_as_string_when_has_data (line 11) | def test_bits_as_string_when_has_data(self):
    method test_bits_as_int_when_no_data (line 18) | def test_bits_as_int_when_no_data(self):
    method test_bits_as_int_when_less_than_a_byte (line 22) | def test_bits_as_int_when_less_than_a_byte(self):
    method test_bits_as_int_when_between_one_and_two_byte (line 27) | def test_bits_as_int_when_between_one_and_two_byte(self):
    method test_bits_append_bit (line 32) | def test_bits_append_bit(self):
    method test_bits_append (line 45) | def test_bits_append(self):
    method test_bits_extend_all (line 52) | def test_bits_extend_all(self):
    method test_bits_extend_other_bits_all (line 59) | def test_bits_extend_other_bits_all(self):
    method test_bits_extend_other_bytes_0_to_not_end (line 66) | def test_bits_extend_other_bytes_0_to_not_end(self):
    method test_bits_extend_other_bytes_not_start_to_end (line 71) | def test_bits_extend_other_bytes_not_start_to_end(self):
    method test_bits_extend_other_bytes_not_start_to_not_end (line 76) | def test_bits_extend_other_bytes_not_start_to_not_end(self):
    method test_bits_xor (line 81) | def test_bits_xor(self):

FILE: test/test_bits_utils.py
  class TestBitUtils (line 6) | class TestBitUtils(unittest.TestCase):
    method test_one_at_normal (line 7) | def test_one_at_normal(self):
    method test_one_at_fail (line 16) | def test_one_at_fail(self):
    method test_zero_at_normal (line 28) | def test_zero_at_normal(self):
    method test_zero_at_fail (line 37) | def test_zero_at_fail(self):
    method test_set_bit_normal (line 51) | def test_set_bit_normal(self):
    method test_set_bit_fail (line 55) | def test_set_bit_fail(self):
    method test_bit_at_normal (line 65) | def test_bit_at_normal(self):
    method test_bit_at_fail (line 73) | def test_bit_at_fail(self):

FILE: test/test_encode_numbers.py
  class TestNumbers (line 6) | class TestNumbers(unittest.TestCase):
    method test_numbers_length_mod_3_is_0 (line 7) | def test_numbers_length_mod_3_is_0(self):
    method test_numbers_length_mod_3_is_1 (line 15) | def test_numbers_length_mod_3_is_1(self):
    method test_numbers_length_mod_3_is_2 (line 24) | def test_numbers_length_mod_3_is_2(self):

FILE: test/test_encode_raw.py
  class TestRaw (line 6) | class TestRaw(unittest.TestCase):
    method test_raw (line 7) | def test_raw(self):
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (123K chars).
[
  {
    "path": ".gitignore",
    "chars": 1179,
    "preview": "# Pycharm files\n.idea/\n\n# personal test file\ntest.py\nexample.jpg\n\n# Created by .ignore support plugin (hsz.mobi)\n### Pyt"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "The MIT License (MIT)\nCopyright (c) 2016 7sDream\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 7730,
    "preview": "# PyQArt - QArt Python implementation\n\n[中文版 README](https://github.com/7sDream/pyqart/blob/master/README.zh.md)\n\n## intr"
  },
  {
    "path": "README.zh.md",
    "chars": 6135,
    "preview": "# PyQArt - QArt 的  Python 实现\n\n[Readme in English](https://github.com/7sDream/pyqart/blob/master/README.md)\n\n## 简介\n\nQArt "
  },
  {
    "path": "pyqart/__init__.py",
    "chars": 234,
    "preview": "from .qr import (\n    QrData,\n    QrPainter,\n    # ------------\n    QrBasePrinter,\n    QrImagePrinter,\n    QrStringPrint"
  },
  {
    "path": "pyqart/art/__init__.py",
    "chars": 26,
    "preview": "from .qart import QArtist\n"
  },
  {
    "path": "pyqart/art/bitblock.py",
    "chars": 2826,
    "preview": "# Added at : 2016.8.3\n# Author   : 7sDream\n# Usage    : A block of bits. In this class, we let each point (including EC)"
  },
  {
    "path": "pyqart/art/exception.py",
    "chars": 191,
    "preview": "# Added at : 2016.8.2\n# Author   : 7sDream\n# Usage    : Exceptions happened at art part.\n\nfrom ..qr import QrException\n\n"
  },
  {
    "path": "pyqart/art/qart.py",
    "chars": 7274,
    "preview": "# Added at : 2016.8.2\n# Author   : 7sDream\n# Usage    : Accept data and source image, make a QArt.\n\nimport itertools\nfro"
  },
  {
    "path": "pyqart/art/source.py",
    "chars": 4580,
    "preview": "# Added at : 2016.8.2\n# Author   : 7sDream\n# Usage    : Source image to make QArt.\n\nfrom random import randint\n\nimport P"
  },
  {
    "path": "pyqart/art/target.py",
    "chars": 930,
    "preview": "# Added at : 2016.8.3\n# Author   : 7sDream\n# Usage    : Target point(contain point and image pixel info).\n\n__all__ = ['T"
  },
  {
    "path": "pyqart/common/__init__.py",
    "chars": 154,
    "preview": "from .bit_funcs import bit_at, set_bit, one_at, zero_at\nfrom .bits import Bits\nfrom .exception import InvalidTypeExcepti"
  },
  {
    "path": "pyqart/common/bit_funcs.py",
    "chars": 1745,
    "preview": "# Added at  : 2016.07.28\n# Author    : 7sDream\n# Usage     : Some common function to process data.\n\nimport functools\n\n\n_"
  },
  {
    "path": "pyqart/common/bits.py",
    "chars": 7049,
    "preview": "# Added at : 2016.7.28\n# Author   : 7sDream\n# Usage    : A utility class provide some bit level operation to bit stream."
  },
  {
    "path": "pyqart/common/exception.py",
    "chars": 689,
    "preview": "# Added at  : 2016.07.30\n# Author    : 7sDream\n# Usage     : Exceptions raised by common functions or classes,\n\n\nclass I"
  },
  {
    "path": "pyqart/qart_entry.py",
    "chars": 4181,
    "preview": "import argparse\nimport sys\nimport time\n\nfrom pyqart.art import QArtist\nfrom pyqart.qr.printer import QrImagePrinter, QrS"
  },
  {
    "path": "pyqart/qr/__init__.py",
    "chars": 342,
    "preview": "from .args import QrArgs\nfrom .data import (\n    QrData,\n    QrDataInvalidException,\n    QrEncodingException,\n    QrSpac"
  },
  {
    "path": "pyqart/qr/args/__init__.py",
    "chars": 25,
    "preview": "from .args import QrArgs\n"
  },
  {
    "path": "pyqart/qr/args/args.py",
    "chars": 7440,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : All needed args to create a empty qr code.\n\nfrom .mask import Q"
  },
  {
    "path": "pyqart/qr/args/mask.py",
    "chars": 1354,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : QrMask represent data part mask of QrCode,\n#            which c"
  },
  {
    "path": "pyqart/qr/args/rotation.py",
    "chars": 664,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : QrRotation represent the rotate of QrCode:\n#               0 fo"
  },
  {
    "path": "pyqart/qr/args/version.py",
    "chars": 2207,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : QrVersion represent version of QrCode, which decide:\n#         "
  },
  {
    "path": "pyqart/qr/data/__init__.py",
    "chars": 226,
    "preview": "from .data import QrData\nfrom .raw import Raw\nfrom .numbers import Numbers\nfrom .alphanumeric import AlphaNumeric\n\nfrom "
  },
  {
    "path": "pyqart/qr/data/alphanumeric.py",
    "chars": 2052,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : Data mode that used to encode\n#            big alpha (A-Z)\n#   "
  },
  {
    "path": "pyqart/qr/data/base.py",
    "chars": 3193,
    "preview": "# Added at : 2016.7.28\n# Author   : 7sDream\n# Usage    : A base data mode class for encoding data to bytes.\n#           "
  },
  {
    "path": "pyqart/qr/data/data.py",
    "chars": 3490,
    "preview": "# Added at : 2016.7.30\n# Author   : 7sDream\n# Usage    : As a data set of (maybe) different data mode thad will be encod"
  },
  {
    "path": "pyqart/qr/data/exception.py",
    "chars": 1627,
    "preview": "# Added at : 2016.7.28\n# Author   : 7sDream\n# Usage    : Exception when encode data is not invalid.\n\nfrom ..exception im"
  },
  {
    "path": "pyqart/qr/data/numbers.py",
    "chars": 1004,
    "preview": "# Added at : 2016.7.28\n# Author   : 7sDream\n# Usage    : Numbers data model, 10 bit for 3 numbers.\n\nfrom .base import Ba"
  },
  {
    "path": "pyqart/qr/data/raw.py",
    "chars": 871,
    "preview": "# Added at : 2016.7.28\n# Author   : 7sDream\n# Usage    : Raw data model, 8 bit for a byte.\n\nfrom .base import BaseType\nf"
  },
  {
    "path": "pyqart/qr/ec/__init__.py",
    "chars": 33,
    "preview": "from .rsencoder import RSEncoder\n"
  },
  {
    "path": "pyqart/qr/ec/gf.py",
    "chars": 2579,
    "preview": "# Added at : 2016.7.31\n# Author   : 7sDream\n# Usage    : Calculate GF(2^m) and all it's item a^n\n\nfrom ...common import "
  },
  {
    "path": "pyqart/qr/ec/poly.py",
    "chars": 3131,
    "preview": "# Added at  : 2016.07.31\n# Author    : 7sDream\n# Usage     : Provide math operator with polynomials on GF28.\n#          "
  },
  {
    "path": "pyqart/qr/ec/rsencoder.py",
    "chars": 1199,
    "preview": "from .poly import GF28Poly\nfrom ...common import Bits\n\n\nclass _RSGenPolynomials(object):\n    def __init__(self):\n       "
  },
  {
    "path": "pyqart/qr/exception.py",
    "chars": 141,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : Base exception.\n\n__all__ = ['QrException']\n\n\nclass QrException("
  },
  {
    "path": "pyqart/qr/painter/__init__.py",
    "chars": 92,
    "preview": "from .painter import QrPainter\nfrom .exception import QrCanvasException, QrPainterException\n"
  },
  {
    "path": "pyqart/qr/painter/canvas.py",
    "chars": 11742,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : A canvas to draw the QrCode. It implements function to draw\n#  "
  },
  {
    "path": "pyqart/qr/painter/exception.py",
    "chars": 301,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : Exception raised when drawing or add data to QrCode.\n\nfrom ..ex"
  },
  {
    "path": "pyqart/qr/painter/painter.py",
    "chars": 4067,
    "preview": "# Added at : 2016.7.30\n# Author   : 7sDream\n# Usage    : A painter that draw paint data to canvas.\n\nfrom random import r"
  },
  {
    "path": "pyqart/qr/painter/point.py",
    "chars": 822,
    "preview": "# Added at : 2016.7.29\n# Author   : 7sDream\n# Usage    : QrPoint represent a point of QrCode, can be 9 type(except UNKNO"
  },
  {
    "path": "pyqart/qr/printer/__init__.py",
    "chars": 167,
    "preview": "from .base import QrBasePrinter\nfrom .image_printer import QrImagePrinter\nfrom .string_printer import QrStringPrinter\nfr"
  },
  {
    "path": "pyqart/qr/printer/base.py",
    "chars": 912,
    "preview": "# Added at : 2016.7.31\n# Author   : 7sDream\n# Usage    : Base printer to visualize QrCode, define the function should be"
  },
  {
    "path": "pyqart/qr/printer/halftone_printer.py",
    "chars": 3040,
    "preview": "from __future__ import division\n\nimport PIL.ImageDraw as Draw\nimport PIL.Image as Image\n\nfrom .image_printer import QrIm"
  },
  {
    "path": "pyqart/qr/printer/image_printer.py",
    "chars": 2657,
    "preview": "# Added at : 2016.7.31\n# Author   : 7sDream\n# Usage    : A printer that print QrCode to a image.\n\nfrom .base import QrBa"
  },
  {
    "path": "pyqart/qr/printer/string_printer.py",
    "chars": 1327,
    "preview": "# Added at : 2016.8.1\n# Author   : 7sDream\n# Usage    : A printer that print QrCode to a string, can be show in shell.\n\n"
  },
  {
    "path": "pyqart/qr_entry.py",
    "chars": 2628,
    "preview": "import argparse\nimport sys\n\nfrom pyqart.qr.data import QrData\nfrom pyqart.qr.painter import QrPainter\nfrom pyqart.qr.pri"
  },
  {
    "path": "setup.py",
    "chars": 1237,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nfrom setuptools import setup, find_packages\n\nimport pyqart\n\npackages = f"
  },
  {
    "path": "test/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/test_alphanumeric.py",
    "chars": 605,
    "preview": "import unittest\n\nfrom pyqart.qr.data.alphanumeric import AlphaNumeric\n\n\nclass TestAlphaNumeric(unittest.TestCase):\n    d"
  },
  {
    "path": "test/test_bits.py",
    "chars": 2560,
    "preview": "import unittest\n\nfrom pyqart.common.bits import Bits\n\n\nclass TestBits(unittest.TestCase):\n    def test_bits_as_string_wh"
  },
  {
    "path": "test/test_bits_utils.py",
    "chars": 3070,
    "preview": "import unittest\n\nfrom pyqart.common.bit_funcs import one_at, zero_at, set_bit, bit_at\n\n\nclass TestBitUtils(unittest.Test"
  },
  {
    "path": "test/test_encode_numbers.py",
    "chars": 880,
    "preview": "import unittest\n\nfrom pyqart.qr.data.numbers import Numbers\n\n\nclass TestNumbers(unittest.TestCase):\n    def test_numbers"
  },
  {
    "path": "test/test_encode_raw.py",
    "chars": 471,
    "preview": "import unittest\n\nfrom pyqart.qr.data.raw import Raw\n\n\nclass TestRaw(unittest.TestCase):\n    def test_raw(self):\n        "
  }
]

About this extraction

This page contains the full source code of the 7sDream/pyqart GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (111.5 KB), approximately 33.2k tokens, and a symbol index with 264 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!