# Закрасили пятую часть QR-кода — читается. Испортили 69 точек вразброс — нет

> Испортили QR-коды четырёх уровней защиты тремя способами: одним пятном, брызгами и отдельными точками. Пятно в центре код уровня H пережил на 19% площади, а 69 точек вразброс (4%) его сломали. Объясняем почему и как сделать свой QR-код, который не подведёт.


Код с паролем от Wi-Fi на холодильнике рано или поздно обрастает кофе, брызгами и потёртостями. Считается, что самый стойкий QR-код восстанавливает около 30% содержимого, — так мы и [писали сами](https://tehprosto.ru/guides/kak-otskanirovat-qr-kod/). Мы испортили больше тысячи кодов. Пятно в центре такой код правда переносит почти на пятую часть площади, а 69 точек вразброс — всего 4% — ломают его наглухо.

<div class="callout callout-info">
<div class="callout-title">📋 Что мы намеряли</div>

Мы сделали QR-коды одной и той же ссылки на всех четырёх уровнях защиты и портили их тремя способами. Одно сплошное пятно в центре код уровня H выдержал на 19% площади. Двадцать мелких брызг — на 9%. А отдельные точки вразброс сломали его уже на 4%: хватило 69 квадратиков из 1681. Закрытый угловой квадрат убивал код любого уровня сразу. В конце — как сделать свой QR-код для гостей или визитки, чтобы он пережил наклейку, кофе и потёртости.
</div>

## Как мы проверяли

Взяли ссылку на ту самую инструкцию — 49 символов — и сделали из неё четыре QR-кода, по одному на каждый уровень защиты. Уровни обозначаются буквами: L восстанавливает 7%, M — 15%, Q — 25%, H — 30%. Это цифры разработчика стандарта, японской компании Denso Wave, которая представила QR-код в 1994 году.

Первое, что бросилось в глаза: коды получились разного размера. Ссылка одна, а квадратиков становится больше. На уровне L код собран из сетки 29×29, на уровне H — уже 41×41. Защита занимает место: чем больше запасных данных, тем плотнее рисунок.

![Четыре QR-кода одной и той же ссылки на уровнях защиты L, M, Q и H: от сетки 29×29 до 41×41](/images/skolko-mozhno-isportit-qr-kod-eksperiment/urovni.webp)
*Одна ссылка, четыре уровня защиты. Чем выше уровень, тем мельче рисунок. Замер «Техпросто»*

Дальше каждый код портили тремя способами:

- **одно пятно** — белый квадрат в центре, как наклейка или логотип; его увеличивали, пока код не переставал читаться;
- **брызги** — от 2 до 30 мелких белых клякс размером 3×3 квадратика, как грязь и капли;
- **точки вразброс** — меняли цвет отдельных квадратиков в случайных местах, белый на чёрный и наоборот, как бывает при царапинах и износе бумаги; угловые квадраты не трогали.

Случайные повреждения повторяли по 20 раз с разной раскладкой, иначе одна удачная попытка дала бы ложную картину. Коды читали три программы-сканера: открытая библиотека ZXing, на основе которой сделаны многие сканеры штрихкодов, и два распознавателя из библиотеки OpenCV. Часть опытов прогнали ещё и через имитацию телефонного снимка: наклон, размытие, шум и сжатие JPEG. Считал всё обычный мини-ПК — тот же, на котором мы проверяли, [за сколько подбирается пароль](https://tehprosto.ru/posts/za-skolko-vzlomayut-parol-eksperiment/). Тысяча с лишним испорченных кодов заняла у него меньше минуты.

Оговоримся сразу: настоящим телефоном мы не сканировали ни одного кода, всё считали распознаватели на картинках. Как поведёт себя дешёвая камера на мятой печати, мы не знаем. Поэтому наши пределы — это потолок, в жизни запас стоит брать меньше.

## Пятно: код переносит заметно больше, чем кажется

Белый квадрат посередине — это логотип или наклейка. Результаты совпали у всех трёх распознавателей до процента:

- уровень **L** читается с пятном на 4,3% площади, а на 5,8% уже нет;
- уровень **M** — 9,2%, ломается на 11%;
- уровень **Q** — 16,4%, ломается на 18,7%;
- уровень **H** — 19,3%, ломается на 21,5%.

Пятая часть кода под заплаткой — и телефон открывает ссылку. Впечатляет, но до обещанных 30% не дотягивает. Дело в том, что стандарт считает свои 30% не от площади, а от байтов данных, — об этом ниже.

На имитации телефонного снимка пределы почти не изменились. Код Q прочитался с пятном на 16,4% во всех десяти попытках, а на 18,7% — ни разу. Разница вышла только на пределе: код H с пятном на 19,3% ZXing прочитал 10 раз из 10, а распознаватели OpenCV — 6 и 4. Разные телефоны в таком случае, скорее всего, тоже поведут себя по-разному.

## Точки вразброс: 69 квадратиков — и всё

Здесь картина перевернулась. Код уровня H, который пережил пятно на 324 квадратика, сдался, когда мы перекрасили всего 69 отдельных точек. Это 4% площади. При 35 испорченных точках он читался всегда, при 58 — в 8 попытках из 20, при 69 — ни разу.

С другими уровнями ещё хуже. Код L уверенно читается при 4 испорченных точках из 841, а при 11 — ни разу. Это чуть больше одного процента площади.

Брызги легли посередине. Код H выдержал двадцать клякс 3×3 во всех попытках. Кляксы ложились случайно и местами перекрывались, так что закрыли они 9,4% площади. На тридцати кляксах код читался уже через раз.

![График: сколько площади QR-кода можно испортить пятном, брызгами и отдельными точками на уровнях L, M, Q и H](/images/skolko-mozhno-isportit-qr-kod-eksperiment/grafik.webp)
*Серые столбцы — обещание стандарта, цветные — что вышло у нас. Чем мельче и разбросаннее повреждение, тем раньше сдаётся код. Замер «Техпросто»*

<div class="callout callout-fact">
<div class="callout-title">🔢 Сколько можно испортить, чтобы код читался 20 раз из 20</div>

| Уровень | Обещано стандартом | Одно пятно | Брызги 3×3 | Точки вразброс |
|---|---|---|---|---|
| L | 7% | 4,3% | 2,1% | 0,5% |
| M | 15% | 9,2% | 4,6% | 1% |
| Q | 25% | 16,4% | 6% | 1,2% |
| H | 30% | 19,3% | 9,4% | 2,1% |

Стандарт считает долю испорченных байтов, наши столбцы — долю площади кода. Распознаватели ZXing и OpenCV, цифровые картинки.
</div>

![Три QR-кода уровня H: с пятном на 19% площади читается, с 69 точками вразброс и с закрытым угловым квадратом — нет](/images/skolko-mozhno-isportit-qr-kod-eksperiment/povrezhdeniya.webp)
*Левый код можно отсканировать прямо с экрана — он откроет нашу инструкцию. Средний и правый ни один из трёх распознавателей не прочитал. Замер «Техпросто»*

## Почему пятно безопаснее россыпи точек

Разгадка в том, как QR-код хранит данные. Данные он пишет не по одному квадратику, а байтами — порциями по восемь квадратиков, которые лежат рядом. И исправляет тоже байтами. Защита работает по коду Рида — Соломона, тому же математическому способу, что спасает музыку на поцарапанных CD. По словам Denso Wave, изначально этот способ защищал связь со спутниками и космическими зондами от помех.

Код Рида — Соломона не различает, сколько квадратиков в байте испорчено: один или все восемь. Байт либо цел, либо его надо чинить. Отсюда и вся разница:

- **пятно** в 324 квадратика задело 48 байтов: квадратики внутри пятна принадлежат одним и тем же байтам;
- **69 точек вразброс** задели в среднем 58 байтов — почти каждая точка испортила свой.

Мы посчитали это по карте кода: какой квадратик к какому байту относится. У нашего кода 172 байта. Они разложены по четырём коробкам по 43 штуки, и в каждой коробке чинится не больше 14. Пятно на 19% испортило в коробках 14, 13, 9 и 12 байтов — ровно на пределе. Стоило увеличить его на один ряд квадратиков, и в первой коробке испорченных стало 15: код перестал читаться. Россыпь из 69 точек переполняет хотя бы одну коробку почти всегда, в наших 20 попытках — каждый раз.

Почему 14, а не больше? Распознаватель не знает, где именно ошибка: перекрашенный квадратик выглядит таким же чистым, как соседи. Поэтому на каждый испорченный байт уходят два запасных: один нужен, чтобы найти место ошибки, второй — чтобы восстановить значение. Это правило Denso Wave приводит у себя на сайте и там же объясняет, что код Рида — Соломона исправляет на уровне байтов и хорошо справляется со сплошными повреждениями.

Отсюда же и разница между обещанными 30% и нашими 19%. Пятно на 19% площади испортило 48 байтов из 172 — это 28%, почти ровно обещание стандарта. Просто пятно режет байты по краям, и каждый обрезок считается целым испорченным байтом. Площадь и байты — разные мерки: в процентах площади запас всегда выходит меньше, чем обещает стандарт.

## Угловой квадрат закрывать нельзя ни на каком уровне

Последний опыт оказался самым жёстким. Мы закрыли белым один из трёх угловых квадратов — от 3 до 6% площади, смотря по уровню. Код не прочитал ни один распознаватель, на всех четырёх уровнях. Закрыли половину квадрата — то же самое.

Код Рида — Соломона здесь бессилен, потому что угловые квадраты не данные. По ним сканер находит код в кадре и понимает, как тот повёрнут. Команда Масахиро Хары, создателя QR-кода, подбирала для этих меток такое соотношение чёрного и белого, которое реже всего встречается на печатной продукции — листовках, журналах, коробках. Так сканер не спутает метку с картинкой вокруг. Положение и поворот кода он определяет по трём квадратам сразу: без одного он не может собрать код и до исправления ошибок не доходит.

<div class="callout callout-warning">
<div class="callout-title">⚠️ Логотип и наклейку — только в центр</div>

Наш опыт показал: закрытый угловой квадрат ломает код любого уровня, даже если закрыта половина. Поэтому логотип ставят только в середину, а наклейку, скотч или ценник клеят мимо углов. Это касается и кода, который вы распечатали для гостей: если его приклеили так, что край загнулся на угловой квадрат, — переклейте.
</div>

<div class="callout callout-info">
<div class="callout-title">📲 Проверяем технику на практике</div>

Такие опыты мы ставим регулярно: сами портим технику и считаем, где предел. Подпишитесь на «Техпросто» в [MAX](https://max.ru/channel_tehprosto), [Telegram](https://t.me/tehprosto) или [Дзене](https://dzen.ru/tehprosto), и новые эксперименты будут приходить сами.
</div>

## Что это значит для вашего собственного QR-кода

Сделать свой QR-код можно за минуту в любом бесплатном генераторе, а сетью Wi-Fi телефон умеет делиться через QR и сам — как это сделать, мы рассказывали в статье [как узнать пароль от Wi-Fi](https://tehprosto.ru/guides/kak-uznat-parol-ot-wifi/). Если код пойдёт в печать, вот что стоит учесть.

<div class="callout callout-tip">
<div class="callout-title">💡 Как сделать QR-код, который не подведёт</div>

1. **В генераторе найдите пункт «Коррекция ошибок»** (по-английски Error correction) и выберите H, если код будет с логотипом, на улице или там, где его трогают руками. Для кода на экране или в чистом месте хватит M — у него меньше квадратиков, они крупнее, и такой код читается издалека. Если такого пункта в генераторе нет, логотип сделайте поменьше или не ставьте вовсе.
2. **Логотип — не больше 15% площади кода.** Наш предел для H — 19%, но это на идеальной картинке. На глаз: логотип шириной в треть кода закрывает около 11% площади.
3. **Угловые квадраты не закрывайте и не обрезайте** — ни логотипом, ни рамкой. Сильную стилизацию углов проверяйте сканером: часть генераторов ломает их пропорции.
4. **Проверьте напечатанный код.** Поцарапайте пробный отпечаток ногтем или брызните на него водой и отсканируйте двумя-тремя телефонами. Читается — запас есть. Палец на экране такого запаса не покажет: он закрывает код одним пятном, а с пятном код справляется лучше всего.
5. **Код H печатайте крупнее:** квадратиков в нём больше, и при той же стороне каждый выходит мельче.
</div>

Многие генераторы по умолчанию ставят уровень M. Это уровень под экран, а не под дверь подъезда. По нашим замерам, M безотказно читается лишь при 1% испорченных точек — это около 11 квадратиков, — а брызги переносит до 4,6% площади. Потёртости и капли выглядят именно так. Если код уходит в печать, настройка по умолчанию работает не на вас.

Если код уже напечатан и плохо читается, сначала протрите его и уберите блик. Остальные причины, по которым телефон не видит код, мы собрали в [инструкции по сканированию](https://tehprosto.ru/guides/kak-otskanirovat-qr-kod/#почему-код-не-читается).

## Частые вопросы

**Почему QR-код с логотипом в центре читается?** Потому что логотип — это одно сплошное пятно, а с таким повреждением код справляется лучше всего. Наш код уровня H пережил заплатку на 19% площади. Но угловые квадраты закрывать нельзя ни на одном уровне.

**Сколько можно закрыть у QR-кода?** Зависит от уровня защиты и от того, как именно закрыть. Одно пятно в центре: от 4% площади на уровне L до 19% на H. Отдельные точки вразброс: от 0,5% до 2% площади.

**Как узнать уровень защиты готового QR-кода?** Сканер уровень обычно не показывает, хотя он записан в самом коде, рядом с угловыми квадратами. На глаз его не угадать: код с логотипом на 6% площади может быть и M, и H. Если код ваш, проще пересоздать его на уровне H, чем гадать.

**Можно ли починить код, который не читается?** Свой — проще перепечатать: это минута в генераторе. Чужой код на табличке или упаковке иногда оживает, если протереть его и убрать блик, — грязь и отражение сканер принимает за испорченные квадратики. Если же стёрт угловой квадрат или большой кусок, чистка не поможет.

QR-код хорошо держит одно большое пятно, заметно хуже — мелкую россыпь и совсем не прощает закрытых углов. Поэтому логотип в центре ему не страшен, а дождь по всей наклейке и загнутый уголок — страшны.

*Если статья помогла — поделитесь с теми, кому может пригодиться. И заходите в наш канал в [MAX](https://max.ru/channel_tehprosto), [Telegram](https://t.me/tehprosto) и [Дзен](https://dzen.ru/tehprosto) — там анонсы новых материалов.*

