Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
main.py548 linesDownload Raw Back to qrcode
1import sys2from bisect import bisect_left3from typing import (4    Dict,5    Generic,6    List,7    NamedTuple,8    Optional,9    Type,10    TypeVar,11    cast,12    overload,13)14 15from typing_extensions import Literal16 17from qrcode import constants, exceptions, util18from qrcode.image.base import BaseImage19from qrcode.image.pure import PyPNGImage20 21ModulesType = List[List[Optional[bool]]]22# Cache modules generated just based on the QR Code version23precomputed_qr_blanks: Dict[int, ModulesType] = {}24 25 26def make(data=None, **kwargs):27    qr = QRCode(**kwargs)28    qr.add_data(data)29    return qr.make_image()30 31 32def _check_box_size(size):33    if int(size) <= 0:34        raise ValueError(f"Invalid box size (was {size}, expected larger than 0)")35 36 37def _check_border(size):38    if int(size) < 0:39        raise ValueError(40            "Invalid border value (was %s, expected 0 or larger than that)" % size41        )42 43 44def _check_mask_pattern(mask_pattern):45    if mask_pattern is None:46        return47    if not isinstance(mask_pattern, int):48        raise TypeError(49            f"Invalid mask pattern (was {type(mask_pattern)}, expected int)"50        )51    if mask_pattern < 0 or mask_pattern > 7:52        raise ValueError(f"Mask pattern should be in range(8) (got {mask_pattern})")53 54 55def copy_2d_array(x):56    return [row[:] for row in x]57 58 59class ActiveWithNeighbors(NamedTuple):60    NW: bool61    N: bool62    NE: bool63    W: bool64    me: bool65    E: bool66    SW: bool67    S: bool68    SE: bool69 70    def __bool__(self) -> bool:71        return self.me72 73 74GenericImage = TypeVar("GenericImage", bound=BaseImage)75GenericImageLocal = TypeVar("GenericImageLocal", bound=BaseImage)76 77 78class QRCode(Generic[GenericImage]):79    modules: ModulesType80    _version: Optional[int] = None81 82    def __init__(83        self,84        version=None,85        error_correction=constants.ERROR_CORRECT_M,86        box_size=10,87        border=4,88        image_factory: Optional[Type[GenericImage]] = None,89        mask_pattern=None,90    ):91        _check_box_size(box_size)92        _check_border(border)93        self.version = version94        self.error_correction = int(error_correction)95        self.box_size = int(box_size)96        # Spec says border should be at least four boxes wide, but allow for97        # any (e.g. for producing printable QR codes).98        self.border = int(border)99        self.mask_pattern = mask_pattern100        self.image_factory = image_factory101        if image_factory is not None:102            assert issubclass(image_factory, BaseImage)103        self.clear()104 105    @property106    def version(self) -> int:107        if self._version is None:108            self.best_fit()109        return cast(int, self._version)110 111    @version.setter112    def version(self, value) -> None:113        if value is not None:114            value = int(value)115            util.check_version(value)116        self._version = value117 118    @property119    def mask_pattern(self):120        return self._mask_pattern121 122    @mask_pattern.setter123    def mask_pattern(self, pattern):124        _check_mask_pattern(pattern)125        self._mask_pattern = pattern126 127    def clear(self):128        """129        Reset the internal data.130        """131        self.modules = [[]]132        self.modules_count = 0133        self.data_cache = None134        self.data_list = []135 136    def add_data(self, data, optimize=20):137        """138        Add data to this QR Code.139 140        :param optimize: Data will be split into multiple chunks to optimize141            the QR size by finding to more compressed modes of at least this142            length. Set to ``0`` to avoid optimizing at all.143        """144        if isinstance(data, util.QRData):145            self.data_list.append(data)146        elif optimize:147            self.data_list.extend(util.optimal_data_chunks(data, minimum=optimize))148        else:149            self.data_list.append(util.QRData(data))150        self.data_cache = None151 152    def make(self, fit=True):153        """154        Compile the data into a QR Code array.155 156        :param fit: If ``True`` (or if a size has not been provided), find the157            best fit for the data to avoid data overflow errors.158        """159        if fit or (self.version is None):160            self.best_fit(start=self.version)161        if self.mask_pattern is None:162            self.makeImpl(False, self.best_mask_pattern())163        else:164            self.makeImpl(False, self.mask_pattern)165 166    def makeImpl(self, test, mask_pattern):167        self.modules_count = self.version * 4 + 17168 169        if self.version in precomputed_qr_blanks:170            self.modules = copy_2d_array(precomputed_qr_blanks[self.version])171        else:172            self.modules = [173                [None] * self.modules_count for i in range(self.modules_count)174            ]175            self.setup_position_probe_pattern(0, 0)176            self.setup_position_probe_pattern(self.modules_count - 7, 0)177            self.setup_position_probe_pattern(0, self.modules_count - 7)178            self.setup_position_adjust_pattern()179            self.setup_timing_pattern()180 181            precomputed_qr_blanks[self.version] = copy_2d_array(self.modules)182 183        self.setup_type_info(test, mask_pattern)184 185        if self.version >= 7:186            self.setup_type_number(test)187 188        if self.data_cache is None:189            self.data_cache = util.create_data(190                self.version, self.error_correction, self.data_list191            )192        self.map_data(self.data_cache, mask_pattern)193 194    def setup_position_probe_pattern(self, row, col):195        for r in range(-1, 8):196 197            if row + r <= -1 or self.modules_count <= row + r:198                continue199 200            for c in range(-1, 8):201 202                if col + c <= -1 or self.modules_count <= col + c:203                    continue204 205                if (206                    (0 <= r <= 6 and c in {0, 6})207                    or (0 <= c <= 6 and r in {0, 6})208                    or (2 <= r <= 4 and 2 <= c <= 4)209                ):210                    self.modules[row + r][col + c] = True211                else:212                    self.modules[row + r][col + c] = False213 214    def best_fit(self, start=None):215        """216        Find the minimum size required to fit in the data.217        """218        if start is None:219            start = 1220        util.check_version(start)221 222        # Corresponds to the code in util.create_data, except we don't yet know223        # version, so optimistically assume start and check later224        mode_sizes = util.mode_sizes_for_version(start)225        buffer = util.BitBuffer()226        for data in self.data_list:227            buffer.put(data.mode, 4)228            buffer.put(len(data), mode_sizes[data.mode])229            data.write(buffer)230 231        needed_bits = len(buffer)232        self.version = bisect_left(233            util.BIT_LIMIT_TABLE[self.error_correction], needed_bits, start234        )235        if self.version == 41:236            raise exceptions.DataOverflowError()237 238        # Now check whether we need more bits for the mode sizes, recursing if239        # our guess was too low240        if mode_sizes is not util.mode_sizes_for_version(self.version):241            self.best_fit(start=self.version)242        return self.version243 244    def best_mask_pattern(self):245        """246        Find the most efficient mask pattern.247        """248        min_lost_point = 0249        pattern = 0250 251        for i in range(8):252            self.makeImpl(True, i)253 254            lost_point = util.lost_point(self.modules)255 256            if i == 0 or min_lost_point > lost_point:257                min_lost_point = lost_point258                pattern = i259 260        return pattern261 262    def print_tty(self, out=None):263        """264        Output the QR Code only using TTY colors.265 266        If the data has not been compiled yet, make it first.267        """268        if out is None:269            import sys270 271            out = sys.stdout272 273        if not out.isatty():274            raise OSError("Not a tty")275 276        if self.data_cache is None:277            self.make()278 279        modcount = self.modules_count280        out.write("\x1b[1;47m" + (" " * (modcount * 2 + 4)) + "\x1b[0m\n")281        for r in range(modcount):282            out.write("\x1b[1;47m  \x1b[40m")283            for c in range(modcount):284                if self.modules[r][c]:285                    out.write("  ")286                else:287                    out.write("\x1b[1;47m  \x1b[40m")288            out.write("\x1b[1;47m  \x1b[0m\n")289        out.write("\x1b[1;47m" + (" " * (modcount * 2 + 4)) + "\x1b[0m\n")290        out.flush()291 292    def print_ascii(self, out=None, tty=False, invert=False):293        """294        Output the QR Code using ASCII characters.295 296        :param tty: use fixed TTY color codes (forces invert=True)297        :param invert: invert the ASCII characters (solid <-> transparent)298        """299        if out is None:300            out = sys.stdout301 302        if tty and not out.isatty():303            raise OSError("Not a tty")304 305        if self.data_cache is None:306            self.make()307 308        modcount = self.modules_count309        codes = [bytes((code,)).decode("cp437") for code in (255, 223, 220, 219)]310        if tty:311            invert = True312        if invert:313            codes.reverse()314 315        def get_module(x, y) -> int:316            if invert and self.border and max(x, y) >= modcount + self.border:317                return 1318            if min(x, y) < 0 or max(x, y) >= modcount:319                return 0320            return cast(int, self.modules[x][y])321 322        for r in range(-self.border, modcount + self.border, 2):323            if tty:324                if not invert or r < modcount + self.border - 1:325                    out.write("\x1b[48;5;232m")  # Background black326                out.write("\x1b[38;5;255m")  # Foreground white327            for c in range(-self.border, modcount + self.border):328                pos = get_module(r, c) + (get_module(r + 1, c) << 1)329                out.write(codes[pos])330            if tty:331                out.write("\x1b[0m")332            out.write("\n")333        out.flush()334 335    @overload336    def make_image(self, image_factory: Literal[None] = None, **kwargs) -> GenericImage:337        ...338 339    @overload340    def make_image(341        self, image_factory: Type[GenericImageLocal] = None, **kwargs342    ) -> GenericImageLocal:343        ...344 345    def make_image(self, image_factory=None, **kwargs):346        """347        Make an image from the QR Code data.348 349        If the data has not been compiled yet, make it first.350        """351        _check_box_size(self.box_size)352        if self.data_cache is None:353            self.make()354 355        if image_factory is not None:356            assert issubclass(image_factory, BaseImage)357        else:358            image_factory = self.image_factory359            if image_factory is None:360                from qrcode.image.pil import Image, PilImage361 362                # Use PIL by default if available, otherwise use PyPNG.363                image_factory = PilImage if Image else PyPNGImage364 365        im = image_factory(366            self.border,367            self.modules_count,368            self.box_size,369            qrcode_modules=self.modules,370            **kwargs,371        )372 373        if im.needs_drawrect:374            for r in range(self.modules_count):375                for c in range(self.modules_count):376                    if im.needs_context:377                        im.drawrect_context(r, c, qr=self)378                    elif self.modules[r][c]:379                        im.drawrect(r, c)380        if im.needs_processing:381            im.process()382 383        return im384 385    # return true if and only if (row, col) is in the module386    def is_constrained(self, row: int, col: int) -> bool:387        return (388            row >= 0389            and row < len(self.modules)390            and col >= 0391            and col < len(self.modules[row])392        )393 394    def setup_timing_pattern(self):395        for r in range(8, self.modules_count - 8):396            if self.modules[r][6] is not None:397                continue398            self.modules[r][6] = r % 2 == 0399 400        for c in range(8, self.modules_count - 8):401            if self.modules[6][c] is not None:402                continue403            self.modules[6][c] = c % 2 == 0404 405    def setup_position_adjust_pattern(self):406        pos = util.pattern_position(self.version)407 408        for i in range(len(pos)):409 410            row = pos[i]411 412            for j in range(len(pos)):413 414                col = pos[j]415 416                if self.modules[row][col] is not None:417                    continue418 419                for r in range(-2, 3):420 421                    for c in range(-2, 3):422 423                        if (424                            r == -2425                            or r == 2426                            or c == -2427                            or c == 2428                            or (r == 0 and c == 0)429                        ):430                            self.modules[row + r][col + c] = True431                        else:432                            self.modules[row + r][col + c] = False433 434    def setup_type_number(self, test):435        bits = util.BCH_type_number(self.version)436 437        for i in range(18):438            mod = not test and ((bits >> i) & 1) == 1439            self.modules[i // 3][i % 3 + self.modules_count - 8 - 3] = mod440 441        for i in range(18):442            mod = not test and ((bits >> i) & 1) == 1443            self.modules[i % 3 + self.modules_count - 8 - 3][i // 3] = mod444 445    def setup_type_info(self, test, mask_pattern):446        data = (self.error_correction << 3) | mask_pattern447        bits = util.BCH_type_info(data)448 449        # vertical450        for i in range(15):451 452            mod = not test and ((bits >> i) & 1) == 1453 454            if i < 6:455                self.modules[i][8] = mod456            elif i < 8:457                self.modules[i + 1][8] = mod458            else:459                self.modules[self.modules_count - 15 + i][8] = mod460 461        # horizontal462        for i in range(15):463 464            mod = not test and ((bits >> i) & 1) == 1465 466            if i < 8:467                self.modules[8][self.modules_count - i - 1] = mod468            elif i < 9:469                self.modules[8][15 - i - 1 + 1] = mod470            else:471                self.modules[8][15 - i - 1] = mod472 473        # fixed module474        self.modules[self.modules_count - 8][8] = not test475 476    def map_data(self, data, mask_pattern):477        inc = -1478        row = self.modules_count - 1479        bitIndex = 7480        byteIndex = 0481 482        mask_func = util.mask_func(mask_pattern)483 484        data_len = len(data)485 486        for col in range(self.modules_count - 1, 0, -2):487 488            if col <= 6:489                col -= 1490 491            col_range = (col, col - 1)492 493            while True:494 495                for c in col_range:496 497                    if self.modules[row][c] is None:498 499                        dark = False500 501                        if byteIndex < data_len:502                            dark = ((data[byteIndex] >> bitIndex) & 1) == 1503 504                        if mask_func(row, c):505                            dark = not dark506 507                        self.modules[row][c] = dark508                        bitIndex -= 1509 510                        if bitIndex == -1:511                            byteIndex += 1512                            bitIndex = 7513 514                row += inc515 516                if row < 0 or self.modules_count <= row:517                    row -= inc518                    inc = -inc519                    break520 521    def get_matrix(self):522        """523        Return the QR Code as a multidimensional array, including the border.524 525        To return the array without a border, set ``self.border`` to 0 first.526        """527        if self.data_cache is None:528            self.make()529 530        if not self.border:531            return self.modules532 533        width = len(self.modules) + self.border * 2534        code = [[False] * width] * self.border535        x_border = [False] * self.border536        for module in self.modules:537            code.append(x_border + cast(List[bool], module) + x_border)538        code += [[False] * width] * self.border539 540        return code541 542    def active_with_neighbors(self, row: int, col: int) -> ActiveWithNeighbors:543        context: List[bool] = []544        for r in range(row - 1, row + 2):545            for c in range(col - 1, col + 2):546                context.append(self.is_constrained(r, c) and bool(self.modules[r][c]))547        return ActiveWithNeighbors(*context)548 
codekingpro/portable-devtools · Team Ai