Skip to content

Commit

Permalink
Merge branch 'release/0.2.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
heuer committed Oct 17, 2018
2 parents f3de9db + 6d7f94e commit eddbe2a
Show file tree
Hide file tree
Showing 60 changed files with 1,606 additions and 136 deletions.
13 changes: 13 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Changes
=======

0.2.8 -- 2018-19-17
-------------------
* Fixed #45: CLI does not raise exceptions but indicates errors with return code 1 and
writes the error message to ``sys.stderr``
* Added experimental ``utils.matrix_iter_detail()`` function which returns an iterator over
the matrix to distinguish different dark and light modules by their function (i.e. separator,
finder pattern etc.)
* Minor performance improvements
* Removed Python 2.6 from test environment
* Added support for vCard TITLE attribute, contributed by Stefano Borini
* Added support for vCard PHOTO URI attribute, suggested by Arthur Reinhart


0.2.7 -- 2018-02-18
-------------------
* Fixed dist package
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2016 - 2017, Lars Heuer
Copyright (c) 2016 - 2018, Lars Heuer
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
Expand Down
6 changes: 3 additions & 3 deletions docs/_static/chart_create.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/_static/chart_png.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/_static/chart_svg.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ Module contents
:members:


Utilities
---------

.. automodule:: segno.utils
:members:



High level QR Code factories
----------------------------

Expand Down
10 changes: 5 additions & 5 deletions docs/comparison-qrcode-libs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Features
Description `qrcode`_ `PyQRCode`_ `qrcodegen`_ `Segno`_
============================================ ================== =================== ================== ========
Library license `BSD`_ `BSD`_ `MIT`_ `BSD`_
Library version 5.3 1.2.1 1.0.0 |version|
Library version 6.0 1.3.0 1.2.0 |version|
Mode Numeric Yes Yes Yes Yes
Mode Alphanumeric Yes Yes Yes Yes
Mode Byte Yes Yes Yes Yes
Expand All @@ -32,16 +32,16 @@ Optimize QR Codes Yes No
`PBM`_ output Yes No No Yes
`PAM`_ output No No No Yes
`LaTeX`_ support No No No Yes
PNG `data URI`_ No kind of (not a URI) No Yes
PNG `data URI`_ No Yes No Yes
SVG data URI No No No Yes
Text output Yes Yes No Yes
`ANSI`_ escape code output Yes Yes No Yes
Other output formats (i.e. `JPEG`_) Yes No No No, but via `PIL plugin`_
Black and white QR Codes Yes Yes Yes Yes
Colored QR Codes No Yes No Yes
Colored QR Codes Yes Yes No Yes
Animated QR Codes (`GIF`_, `APNG`_) No No No No
Changing size of modules (scaling factor) Yes Yes No Yes
Command line script Yes No No Yes
Command line script Yes Yes No Yes
Plugins No No No Yes
Default encoding in Byte mode UTF-8 ISO/IEC 8859-1 UTF-8 ISO/IEC 8859-1
or UTF-8 or UTF-8
Expand All @@ -58,7 +58,7 @@ Performance
-----------

Some performance indicators. The script `benchmarks.py`_ ran on a
MacBook Air 2,13 Core2 Duo using CPython 2.7.10. Each SVG / PNG image uses a
Mac Mini 2,26 Core2 Duo using CPython 2.7.14. Each SVG / PNG image uses a
scaling factor of 10 (aside from qrcodegen which does not support any scaling).


Expand Down
15 changes: 15 additions & 0 deletions docs/serializers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,20 @@ for details.
>>> qr.save('neil-young-5.svgz', color=(8, 90, 117))
If the QR Code should be serialized to a buffer, use the ``kind`` parameter
to specify the output format.

.. code-block:: python
>>> import segno
>>> import io
>>> qr = segno.make('Neil Young')
>>> buff = io.BytesIO()
>>> qr.save(buff, kind='svg')
>>> # All other serializer parameters are supported as well
>>> buff = io.BytesIO()
>>> qr.save(buff, kind='svg', color='#ccc', background='green')
See :py:meth:`segno.QRCode.save` for a complete reference which parameters are
accepted by the specific serializer.
3 changes: 2 additions & 1 deletion sandbox/make_charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Create the benchmark charts.
"""
import csv
from decimal import Decimal
import pygal


Expand Down Expand Up @@ -40,7 +41,7 @@ def create_charts():
(svg_data, 'Create a 1-M QR Code and write SVG', 'out/chart_svg.svg'),
(png_data, 'Create a 1-M QR Code and write PNG', 'out/chart_png.svg')):
create_chart(title,
[(name, [{'value': float(val), 'color': color_map[name], 'label': name}]) for name, val in data],
[(name, [{'value': float(val), 'color': color_map[name], 'label': name}]) for name, val in sorted(data, key=lambda t: Decimal(t[1]))],
filename)


Expand Down
6 changes: 3 additions & 3 deletions sandbox/out/chart_create.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions sandbox/out/chart_png.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions sandbox/out/chart_svg.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 12 additions & 12 deletions sandbox/out/results.csv
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
PyQRCode create,33.64
qrcodegen create,23.57
qrcode create,32.97
Segno create,23.49
PyQRCode SVG,45.66
qrcodegen SVG,26.71
qrcode SVG path,96.73
qrcode SVG rects,80.07
Segno SVG,25.19
PyQRCode PNG,113.77
qrcode PNG,43.20
Segno PNG,31.81
PyQRCode create,30.10
qrcodegen create,16.76
qrcode create,12.29
Segno create,13.46
PyQRCode SVG,31.62
qrcodegen SVG,17.97
qrcode SVG path,60.00
qrcode SVG rects,53.79
Segno SVG,14.25
PyQRCode PNG,119.23
qrcode PNG,17.16
Segno PNG,19.01
32 changes: 24 additions & 8 deletions segno/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
except NameError: # pragma: no cover
str_type = str

__version__ = '0.2.7'
__version__ = '0.2.8'

__all__ = ('make', 'make_qr', 'make_micro', 'make_sequence', 'QRCode',
'QRCodeSequence', 'QRCodeError', 'ErrorLevelError', 'ModeError',
Expand Down Expand Up @@ -182,10 +182,11 @@ def make_sequence(content, error=None, version=None, mode=None, mask=None,
"""\
Creates a sequence of QR Codes.
If the content fits into one QR Code and neither `version` is not provided,
this function may return a sequence with one QR Code which
does not use the Structured Append mode. Otherwise a sequence of 2 .. n
(max. n = 16) QR Codes is returned which use the Structured Append mode.
If the content fits into one QR Code and neither ``version`` nor
``symbol_count`` is provided, this function may return a sequence with
one QR Code which does not use the Structured Append mode. Otherwise a
sequence of 2 .. n (max. n = 16) QR Codes is returned which use the
Structured Append mode.
The Structured Append mode allows to split the content over a number
(max. 16) QR Codes.
Expand All @@ -197,8 +198,8 @@ def make_sequence(content, error=None, version=None, mode=None, mask=None,
.. code-block:: python
for qrcode in segno.make_sequence(data, symbol_count=2):
qrcode.save('seq.svg', scale=10, color='darkblue')
for i, qrcode in enumerate(segno.make_sequence(data, symbol_count=2)):
qrcode.save('seq-%d.svg' % i, scale=10, color='darkblue')
The returned number of QR Codes is determined by the `version` or
`symbol_count` parameter
Expand Down Expand Up @@ -491,6 +492,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.BytesIO
kind "svg" or "svgz" (to create a gzip compressed SVG)
scale integer or float
color Default: "#000" (black)
Expand Down Expand Up @@ -564,6 +566,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.BytesIO
kind "png"
scale integer
color Default: "#000" (black)
Expand All @@ -589,6 +592,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.StringIO
kind "eps"
scale integer or float
color Default: "#000" (black)
Expand All @@ -601,6 +605,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.BytesIO
kind "pdf"
scale integer or float
compresslevel Default: 9. Integer indicating the compression level.
Expand All @@ -616,6 +621,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.StringIO
kind "txt"
color Default: "1"
background Default: "0"
Expand All @@ -638,6 +644,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.BytesIO
kind "pbm"
scale integer
plain Default: False. Boolean to switch between the P4 and P1 format.
Expand All @@ -651,6 +658,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.BytesIO
kind "pam"
scale integer
color Default: "#000" (black).
Expand All @@ -661,16 +669,22 @@ def save(self, out, kind=None, **kw):
**LaTeX / PGF/TikZ**
To use the output of this serializer, the ``PGF/TikZ`` (and optionally
``hyperref``) package is required in the LaTeX environment. The
serializer itself does not depend on any external packages.
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.StringIO
kind "tex"
scale integer or float
color LaTeX color name (default: "black"). The color is written
"at it is", so ensure that the color is a standard color or it
has been defined in the enclosing LaTeX document.
url Default: ``None``. Optional URL where the QR Code should
point to. Requires the hyperref package.
point to. Requires the ``hyperref`` package in your LaTeX
environment.
============= ==============================================================
Expand All @@ -679,6 +693,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.StringIO
kind "xbm"
scale integer
name Name of the variable (default: "img")
Expand All @@ -690,6 +705,7 @@ def save(self, out, kind=None, **kw):
============= ==============================================================
Name Description
============= ==============================================================
out Filename or io.StringIO
kind "xpm"
scale integer
color Default: "#000" (black).
Expand Down
8 changes: 7 additions & 1 deletion segno/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"QR Code" and "Micro QR Code" are registered trademarks of DENSO WAVE INCORPORATED.
"""
from __future__ import absolute_import, unicode_literals
import os
import sys
import argparse
import segno
Expand Down Expand Up @@ -192,12 +193,17 @@ def make_code(config):

def main(args=sys.argv[1:]):
config = parse(args)
qr = make_code(config)
try:
qr = make_code(config)
except segno.QRCodeError as ex:
sys.stderr.writelines([str(ex), os.linesep])
return sys.exit(1)
output = config.pop('output')
if output is None:
qr.terminal(border=config['border'])
else:
qr.save(output, **build_config(config, filename=output))
return 0


class _AttrDict(dict):
Expand Down
26 changes: 13 additions & 13 deletions segno/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import re
import math
import codecs
from copy import deepcopy
from collections import namedtuple
from . import consts
_PY2 = False
Expand Down Expand Up @@ -292,7 +291,7 @@ def _encode(segments, error, version, mask, eci, boost_error, sa_info=None):
add_codewords(matrix, buff, version)
# ISO/IEC 18004:2015(E) -- 7.8.2 Data mask patterns (page 50)
# ISO/IEC 18004:2015(E) -- 7.8.3 Evaluation of data masking results (page 53)
matrix, mask = find_best_mask(matrix, version, is_micro, mask)
mask = find_and_apply_best_mask(matrix, version, is_micro, mask)
# ISO/IEC 18004:2015(E) -- 7.9 Format information (page 55)
add_format_info(matrix, version, error, mask)
# ISO/IEC 18004:2015(E) -- 7.10 Version information (page 58)
Expand Down Expand Up @@ -652,7 +651,7 @@ def make_error_block(ec_info, data_block):
return error_block[len_data:]


def find_best_mask(matrix, version, is_micro, proposed_mask=None):
def find_and_apply_best_mask(matrix, version, is_micro, proposed_mask=None):
"""\
Applies all mask patterns against the provided QR Code matrix and returns
the best matrix and best pattern.
Expand Down Expand Up @@ -700,19 +699,20 @@ def is_encoding_region(i, j):
if proposed_mask is not None:
apply_mask(matrix, mask_patterns[proposed_mask], matrix_size,
is_encoding_region)
return matrix, proposed_mask
return proposed_mask

for mask_number, mask_pattern in enumerate(mask_patterns):
masked_matrix = deepcopy(matrix)
apply_mask(masked_matrix, mask_pattern, matrix_size, is_encoding_region)
apply_mask(matrix, mask_pattern, matrix_size, is_encoding_region)
# NOTE: DO NOT add format / version info in advance of evaluation
# See ISO/IEC 18004:2015(E) -- 7.8. Data masking (page 50)
score = eval_mask(masked_matrix, matrix_size)
score = eval_mask(matrix, matrix_size)
if is_better(score, best_score):
best_score = score
best_matrix = masked_matrix
best_pattern = mask_number
return best_matrix, best_pattern
# Undo mask
apply_mask(matrix, mask_pattern, matrix_size, is_encoding_region)
apply_mask(matrix, mask_patterns[best_pattern], matrix_size, is_encoding_region)
return best_pattern


def apply_mask(matrix, mask_pattern, matrix_size, is_encoding_region):
Expand Down Expand Up @@ -1221,14 +1221,14 @@ def make_matrix(version, reserve_regions=True, add_timing=True):
if version > 6:
# Reserve version pattern areas
for i in range(6):
# Lower left
matrix[-11][i] = 0x0
matrix[-10][i] = 0x0
matrix[-9][i] = 0x0
# Upper right
matrix[i][-11] = 0x0
matrix[i][-10] = 0x0
matrix[i][-9] = 0x0
# Lower left
matrix[-11][i] = 0x0
matrix[-10][i] = 0x0
matrix[-9][i] = 0x0
# Reserve format pattern areas
for i in range(9):
matrix[i][8] = 0x0 # Upper left
Expand Down

0 comments on commit eddbe2a

Please sign in to comment.