Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.65/82: Рейтинг темы: голосов - 82, средняя оценка - 4.65
+1
345 / 178 / 53
Регистрация: 24.08.2010
Сообщений: 1,028

QR код всегда разный

25.05.2017, 07:47. Показов 15863. Ответов 27
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет.
Почему в разных программах, онлайн кодировщиках, QR код из одного и того же текста получается разный?
Вот есть чек
Название: С чека.jpg
Просмотров: 244

Размер: 8.1 Кб
текст в онлайн читалках расшифровывается как
t=20170523T2134&s=630.21&fn=871000010017 1999&i=990&fp=1042167885&n=1
и я ему верю, цифры с чека сходятся.

А вот создать QR код по той же строке, в разных программах генерируется везде разный рисунок.
Название: imageOnline.png
Просмотров: 241

Размер: 524 байтНазвание: QR_Gen_C++.jpg
Просмотров: 239

Размер: 17.0 Кб

Мне нужно сделать картинку QR кода как на чеке.
И прикрутить реализацию в билдер.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.05.2017, 07:47
Ответы с готовыми решениями:

Синий экран смерти, при том всегда разный
Здравствуйте форумчане! У меня проблема с синим экраном началась недавно. Комп новый (3 месяца), собирался вручную, все работало идеально,...

При автозапуске Мозилы дополнительно всплывает один рекламный сайт, всегда разный
При автозапуске Мозилы дополнительно всплывает один рекламный сайт, всегда разный. Мозилу переустановил, host подправил - ничего не...

Разный исходный код
Здрасте. проблема такая: есть сайт на движке Джумла, с него надо выдрать исходный код. с помощью IdHTTP достаёт, в Memo кладёт. но проблема...

27
 Аватар для Dinkin
783 / 556 / 136
Регистрация: 31.05.2013
Сообщений: 3,153
Записей в блоге: 3
25.05.2017, 10:55
Могу предположить.
Что распознание QR кода проходит с неточностью (такое не редкость когда QR код мелкого размера и точки замылины). в следствии чего на выходе имеет другое значение....ну далее конечно же кодируется в другой узор.
0
+1
345 / 178 / 53
Регистрация: 24.08.2010
Сообщений: 1,028
25.05.2017, 12:26  [ТС]
Цитата Сообщение от +1 Посмотреть сообщение
текст в онлайн читалках расшифровывается как
t=20170523T2134&s=630.21&fn=871000010017 1999&i=990&fp=1042167885&n=1
В разных читает одинаково. Но это не главное.
Почему, когда вставляю этот текст в генератор QR кода, на одну и ту же строку везде получаются разные картинки?
0
 Аватар для Dinkin
783 / 556 / 136
Регистрация: 31.05.2013
Сообщений: 3,153
Записей в блоге: 3
25.05.2017, 12:31
Цитата Сообщение от +1 Посмотреть сообщение
текст в онлайн читалках расшифровывается как
Это не показатель...вполне может быть так пропечаталось на чеке. Алгоритм распознания то у всех один и тот же.

Цитата Сообщение от +1 Посмотреть сообщение
Почему на одну и ту же строку везде получаются разные картинки?
У меня как то была необходимость вставлять QR код к письму, и я столкнулся с тем что есть "Старые"
и "Новые" алгоритмы кодировки. Они давали разный узор, но при расшифровки все было впорядке.

PS. Так же в интернете натыкался на несколько глючных кодировщиков...которые в обще в хрень кодировали.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33398 / 21508 / 8236
Регистрация: 22.10.2011
Сообщений: 36,906
Записей в блоге: 12
25.05.2017, 12:32
Цитата Сообщение от +1 Посмотреть сообщение
на одну и ту же строку
А кодировка, с которой они работают, тоже одна и та же?
0
place status here
 Аватар для gunslinger
3190 / 2227 / 640
Регистрация: 20.07.2013
Сообщений: 6,023
25.05.2017, 12:40
Может потому, что QR-код является избыточным (судя по википедии, содержит от 7 до 30% "лишней" информации)?
0
+1
345 / 178 / 53
Регистрация: 24.08.2010
Сообщений: 1,028
25.05.2017, 19:01  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
А кодировка, с которой они работают, тоже одна и та же?
По-разному пробовал
0
+1
345 / 178 / 53
Регистрация: 24.08.2010
Сообщений: 1,028
25.05.2017, 19:02  [ТС]
Цитата Сообщение от gunslinger Посмотреть сообщение
Может потому, что QR-код является избыточным
Как победить?
0
place status here
 Аватар для gunslinger
3190 / 2227 / 640
Регистрация: 20.07.2013
Сообщений: 6,023
26.05.2017, 01:10
Не знаю. Вопрос в том, а нужно ли это?
0
+1
345 / 178 / 53
Регистрация: 24.08.2010
Сообщений: 1,028
26.05.2017, 12:48  [ТС]
Нашел на одном сайте побайтную расшифровку:

Raw text
t=20170523T2134&s=630.21&fn=871000010017 1999&i=990&fp=1042167885&n=1

Raw bytes
40 27 43 d1 02 0c 9b 04 ba 00 aa 08 08 6a a2 06
93 39 9e 9b 19 98 17 19 18 93 33 37 1e 88 21 b3
80 00 50 22 63 ca 05 13 34 9e 9c 9c 98 13 33 38
1e 88 14 34 1b 18 a2 a0 21 33 71 e9 88 00 ec 11
ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11
ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11
ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11
ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11
ec 11 ec 11 ec 11 ec 11

Barcode format QR_CODE
Parsed Result Type TEXT
Parsed Result
t=20170523T2134&s=630.21&fn=871000010017 1999&i=990&fp=1042167885&n=1
Видно, что в конце есть ниочёмная инфа.
А как эти байты преобразовать в текст не пойму.
В строке 68 символов.
Тут получается только 63.
Что за кодировка?
В hex тоже непонятно.
0
Заблокирован
02.05.2023, 20:05
Тоже искал ответ на данный вопрос, поэтому попал сюда. Разобрался. Сейчас объясню, если кому-то ещё интересно.

Вот такой же символ получился, как на чеке: QR Ver=6, ECL=Low, Mask=4 (маску в этом ПО задать нельзя).
Code
1
t=20170523T2134&s=630.21&fn=8710000100171999&i=990&fp=1042167885&n=1

Видимо, в кассах Атол используется код ByteScout.

А вот его декодирование (Raw bytes получены на https://zxing.org/w/decode):
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
40 27 43 D1 02 0C 9B 04   BA 00 AA 08 08 6A A2 06
93 39 9E 9B 19 98 17 19   18 93 33 37 1E 88 21 B3
80 00 50 22 63 CA 05 13   34 9E 9C 9C 98 13 33 38
1E 88 14 34 1B 18 A2 A0   21 33 71 E9 88 00 EC 11
EC 11 EC 11 EC 11 EC 11   EC 11 EC 11 EC 11 EC 11
EC 11 EC 11 EC 11 EC 11   EC 11 EC 11 EC 11 EC 11
EC 11 EC 11 EC 11 EC 11   EC 11 EC 11 EC 11 EC 11
EC 11 EC 11 EC 11 EC 11   EC 11 EC 11 EC 11 EC 11
EC 11 EC 11 EC 11 EC 11
 
4    0   2    7   4    3   D    1    0   2   0    C   9    B   0   4    B   A    0    0   A    A   0    8    0   8    6   A   A    2    0    6   9    3   3    9   9    E   9    B   1    9   9    8   1    7   1    9   1    8   9    3   3    3   3    7   1    E   8    8    2   1    B   3   8    0   0    0   5   0    2   2    6   3   C    A    0    5   1    3   3    4   9    E   9    C   9    C   9    8   1    3   3    3   3    8   1    E   8    8    1   4    3   4   1    B   1    8   A   2    A    0    2   1    3   3    7   1    E   9    8   8    0    0   E   C   1   1
0100 00000010 01110100 00111101 0001 0000001000 0011001001 1011000001 0010111 0100 00000001 01010100 0001 0000000100 0011010101 0100 0100 00001101 00100110 01110011 00111101 00110110 00110011 00110000 00101110 00110010 00110001 00100110 01100110 01101110 00111101 0001 0000010000 1101100111 0000000000 0000001010 0000010001 0011000111 1001 0100 00001010 00100110 01101001 00111101 00111001 00111001 00110000 00100110 01100110 01110000 00111101 0001 0000001010 0001101000 0011011000 1100010100 0101 0100 00000100 00100110 01101110 00111101 00110001 0000 00000001110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001111011000001000111101100000100011110110000010001
              t        =                        201        705        23                    T                        213        4                  &        s        =        6        3        0        .        2        1        &        f        n        =                        871        000        010        017        199        9                  &        i        =        9        9        0        &        f        p        =                        104        216        788        5                  &        n        =        1
Для понимания, что здесь происходит, достаточно статьи в Википедии про QR-код. Как видно, текст сегментирован, видимо, для уменьшения размера кодируемых данных. Начинаются данные с 4 бит 0100, что означает режим байтового кодирования, дальше 8 бит - количество символов 2 (t=), далее 16 бит - коды этих символов в UTF-8 (латиница в UTF-8 совпадает с ASCII). Затем происходит смена режима кодирования на цифровое, на которые указывают следующие 4 бита 0001 и 10 бит 0000001000 - количество символов 8 (20170523). Потом опять переход на байтовое кодирование и т. д. В конце текста 4 бита 0000, и далее - набивка.

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

Теперь по поводу Билдера (может, кому-то актуально, хотя, Билдер здесь ни при чём ).

Я использую C-реализацию библиотеки QR Code generator library https://www.nayuki.io/page/qr-... or-library, скорректировав её немного под себя.

Вот код, который используется между приложением и этой библиотекой (функции библиотеки в методах класса QRCodeEnc).
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
#pragma hdrstop
 
#include "BarCode.h"
//---------------------------------------------------------------------------
 
#pragma package(smart_init)
//---------------------------------------------------------------------------
 
namespace Barcode {
//---------------------------------------------------------------------------
 
bool __fastcall CheckIfChangeModeOpimized(DynamicArray <QRCode_Segment> &segments, int segIndex)
{
    bool result = true;
    if (segIndex > 0 && segments[segIndex].bitLength != -1/*LENGTH_OVERFLOW*/ && segments[segIndex - 1].bitLength != -1/*LENGTH_OVERFLOW*/)
    {
        if (segments[segIndex - 1].mode == segments[segIndex].mode)
            result = false;
        else if (segments[segIndex - 1].mode > segments[segIndex].mode)
        {
            int bitLength = QRCodeEnc::CalcSegmentBitLength(segments[segIndex - 1].mode, segments[segIndex - 1].numChars + segments[segIndex].numChars);
            int modeAndLenBitLength;
            if (segments[segIndex].mode == QRCode_Mode_NUMERIC)
                modeAndLenBitLength = 4 + 10;// + 4;
            else if (segments[segIndex].mode == QRCode_Mode_ALPHANUMERIC)
                modeAndLenBitLength = 4 + 9;// + 4;
            if (segments[segIndex - 1].bitLength + modeAndLenBitLength + segments[segIndex].bitLength >= bitLength)
            {
                result = false;
                //segments[segIndex - 1].bitLength = bitLength;
            }
        }
    }
    return result;
}
//---------------------------------------------------------------------------
 
TBytes __fastcall QRCodeEncode (const UTF8String &text, bool splitIntoSegments, int &version, QRCode_Ecc &ecl, QRCode_Mask &mask, bool eclBoost)
{
    TBytes tempBuffer, qrcode;
    qrcode.Length = QRCode_BUFFER_LEN_MAX;
    tempBuffer.Length = qrcode.Length;
    int dataLen = text.Length();
    bool res = false;
    if (splitIntoSegments && dataLen > 0)
    {
        DynamicArray <QRCode_Segment> segments;
        DynamicArray <TBytes> buffers;
 
        // Split data into segments and calculate the size of the segments
        int l;
        char* data = text.c_str();
        QRCode_Mode currMode, mode = (QRCode_Mode)0;
        for (int i = 0; i < dataLen; ++i, ++data)
        {
            if (*data >= '0' && *data <= '9')
                currMode = QRCode_Mode_NUMERIC; // 0x1
            else if (QRCodeEnc::IsAlphanumericLatinChar(*data))
                currMode = QRCode_Mode_ALPHANUMERIC; // 0x2
            else
                currMode = QRCode_Mode_BYTE; // 0x4
            if (mode != currMode)
            {
                mode = currMode;
                int segIndex = segments.Length;
                segments.Length = segIndex + 1;
                segments[segIndex].mode = mode;
                if (segIndex > 0)
                {
                    segments[segIndex - 1].numChars = i - l; // Data size in bytes
                    segments[segIndex - 1].bitLength = QRCodeEnc::CalcSegmentBitLength(segments[segIndex - 1].mode, segments[segIndex - 1].numChars); // Segment bit length
                    if (!CheckIfChangeModeOpimized(segments, segIndex - 1))
                    {
                        segments[segIndex - 2].numChars += segments[segIndex - 1].numChars;
                        segments[segIndex - 2].bitLength = QRCodeEnc::CalcSegmentBitLength(segments[segIndex - 2].mode, segments[segIndex - 2].numChars);
                        segments[segIndex - 1] = segments[segIndex];
                        segments.Length = segIndex;
                    }
                }
                l = i;
            }
        }
        segments[segments.Length - 1].numChars = dataLen - l;
        if (!CheckIfChangeModeOpimized(segments, segments.Length - 1))
        {
            segments[segments.Length - 2].numChars += segments[segments.Length - 1].numChars;
            segments[segments.Length - 2].bitLength = QRCodeEnc::CalcSegmentBitLength(segments[segments.Length - 2].mode, segments[segments.Length - 2].numChars);
            segments.Length = segments.Length - 1;
        }
 
        // Another segment optimization
        l = 0;
        for (int i = 0; i < segments.Length - 2; ++i)
        {
            l += segments[i].numChars;
            if (segments[i].mode == segments[i + 2].mode && segments[i].mode > segments[i + 1].mode && segments[i].bitLength != -1/*LENGTH_OVERFLOW*/ && segments[i + 1].bitLength != -1/*LENGTH_OVERFLOW*/ && segments[i + 2].bitLength != -1/*LENGTH_OVERFLOW*/)
            {
                int bitLength = QRCodeEnc::CalcSegmentBitLength(segments[i].mode, segments[i].numChars + segments[i + 1].numChars + segments[i + 2].numChars);
                int modeAndLenBitLength1;
                if (segments[i + 1].mode == QRCode_Mode_NUMERIC)
                    modeAndLenBitLength1 = 4 + 10;// + 4;
                else if (segments[i + 1].mode == QRCode_Mode_ALPHANUMERIC)
                    modeAndLenBitLength1 = 4 + 9;// + 4;
                int modeAndLenBitLength2;
                if (segments[i + 2].mode == QRCode_Mode_ALPHANUMERIC)
                    modeAndLenBitLength2 = 4 + 9;// + 4;
                else if (segments[i + 2].mode == QRCode_Mode_BYTE)
                    modeAndLenBitLength2 = 4 + 8;// + 8;
                if (segments[i].bitLength + modeAndLenBitLength1 + segments[i + 1].bitLength + modeAndLenBitLength2 + segments[i + 2].bitLength >= bitLength)
                {
                    segments[i].numChars += segments[i + 1].numChars + segments[i + 2].numChars;
                    segments[i].bitLength = QRCodeEnc::CalcSegmentBitLength(segments[i].mode, segments[i].numChars);
                    for (int j = i + 3; j < segments.Length; ++j)
                        segments[j - 2] = segments[j];
                    segments.Length = segments.Length - 2;
                }
            }
        }
 
        // Prepare the segments
        buffers.Length = segments.Length;
        data = text.c_str();
        res = true;
        for (int i = 0; res && i < segments.Length; ++i)
        {
            l = segments[i].numChars;
            if (segments[i].mode == QRCode_Mode_NUMERIC)
            {
                res = QRCodeEnc::CalcSegmentBufferSize(QRCode_Mode_NUMERIC, l) <= (size_t)tempBuffer.Length;
                if (res)
                {
                    segments[i] = QRCodeEnc::MakeNumeric(data, l, &tempBuffer[0]);
                    res = segments[i].bitLength != -1/*LENGTH_OVERFLOW*/;
                    data += l;
                }
            }
            else if (segments[i].mode == QRCode_Mode_ALPHANUMERIC)
            {
                res = QRCodeEnc::CalcSegmentBufferSize(QRCode_Mode_ALPHANUMERIC, l) <= (size_t)tempBuffer.Length;
                if (res)
                {
                    segments[i] = QRCodeEnc::MakeAlphanumeric(data, l, &tempBuffer[0]);
                    res = segments[i].bitLength != -1/*LENGTH_OVERFLOW*/;
                    data += l;
                }
            }
            else
            {
                res = l <= tempBuffer.Length;
                if (res)
                {
                    segments[i] = QRCodeEnc::MakeBytes(data, l, &tempBuffer[0]);
                    res = segments[i].bitLength != -1/*LENGTH_OVERFLOW*/;
                    data += l;
                }
            }
 
            if (res)
            {
                buffers[i].Length = segments[i].bitLength / 8 + (segments[i].bitLength % 8 > 0);
                segments[i].data = &buffers[i][0];
                memcpy(segments[i].data, &tempBuffer[0], buffers[i].Length);
            }
        }
 
        if (res)
            res = QRCodeEnc::EncodeSegmentsAdvanced(&segments[0],
                                                    segments.Length,
                                                    version,
                                                    QRCode_Ver_MAX, /* The smallest possible version within the given range is automatically chosen */
                                                    mask,
                                                    ecl, /* Error correction level */
                                                    eclBoost, /* true - The highest possible error correction level without increasing the version */
                                                    &tempBuffer[0],
                                                    &qrcode[0]
            );
    }
    else
    {
        res = QRCodeEnc::EncodeText(text.c_str(),
                                    &tempBuffer[0],
                                    &qrcode[0],
                                    version,
                                    QRCode_Ver_MAX, /* The smallest possible version within the given range is automatically chosen */
                                    mask,
                                    ecl, /* Error correction level */
                                    eclBoost /* true - The highest possible error correction level without increasing the version */
        );
    }
    if (res)
    {
        //int size = QRCodeEnc::GetSize(&qrcode[0]);
        //version = QRCodeEnc::GetVersion(size);
        qrcode.Length = QRCode_BUFFER_LEN_FOR_VERSION(version);
    }
    else
        qrcode.Length = 0;
    return qrcode;
}
//---------------------------------------------------------------------------
 
TBytes __fastcall QRCodeEncodeBin (const void* data, size_t dataLength, int &version, QRCode_Ecc &ecl, QRCode_Mask &mask, bool eclBoost)
{
    TBytes tempBuffer, qrcode;
    qrcode.Length = QRCode_BUFFER_LEN_MAX;
    tempBuffer.Length = qrcode.Length;
    memcpy(&tempBuffer[0], data, dataLength);
    bool res = QRCodeEnc::EncodeBinary( &tempBuffer[0],
                                        dataLength,
                                        &qrcode[0],
                                        version,
                                        QRCode_Ver_MAX, /* The smallest possible version within the given range is automatically chosen */
                                        mask,
                                        ecl, /* Error correction level */
                                        eclBoost /* true - The highest possible error correction level without increasing the version */
    );
    if (res)
    {
        //int size = QRCodeEnc::GetSize(&qrcode[0]);
        //version = QRCodeEnc::GetVersion(size);
        qrcode.Length = QRCode_BUFFER_LEN_FOR_VERSION(version);
    }
    else
        qrcode.Length = 0;
    return qrcode;
}
//---------------------------------------------------------------------------
 
Graphics::TBitmap* __fastcall QRCodeGetBMP (TBytes qrcode, TColor clrBase, TColor clrModule, size_t sizePxModule, size_t sizePxMargin)
{
    Graphics::TBitmap* bmp = new Graphics::TBitmap();
    try
    {
        if (clrBase != Graphics::clNone)
        {
            bmp->SetSize(0, 0);
            bmp->Canvas->Brush->Color = clrBase;
        }
        size_t size = QRCodeEnc::GetSize(&qrcode[0]);
        bmp->SetSize(sizePxModule * size + sizePxMargin * 2, sizePxModule * size + sizePxMargin * 2);
        bmp->Canvas->Brush->Color = clrModule;
        TRect rect(sizePxMargin, sizePxMargin, sizePxMargin + sizePxModule, sizePxMargin + sizePxModule);
        for (size_t y = 0; y < size; ++y)
        {
            OffsetRect(rect, sizePxMargin - rect.left, 0);
            for (size_t x = 0; x < size; ++x)
            {
                if (QRCodeEnc::GetModule(&qrcode[0], x, y))
                    bmp->Canvas->FillRect(rect);
                OffsetRect(rect, rect.Width(), 0);
            }
            OffsetRect(rect, 0, rect.Height());
        }
    }
    catch (...)
    {
        delete bmp;
        bmp = NULL;
    }
    return bmp;
}
//---------------------------------------------------------------------------
 
UTF8String __fastcall QRCodeGetSVG (TBytes qrcode, TColor clrBase, TColor clrModule, size_t sizeMargin)
{
    int size = QRCodeEnc::GetSize(&qrcode[0]);
    UTF8String sSize = IntToStr(size + (int)sizeMargin * 2) + L" " + IntToStr(size + (int)sizeMargin * 2);
    clrBase = (Graphics::TColor)ColorToRGB(clrBase);
    clrModule = (Graphics::TColor)ColorToRGB(clrModule);
    UTF8String sClrBase   = IntToHex(GetRValue(clrBase), 2) + IntToHex(GetGValue(clrBase), 2) + IntToHex(GetBValue(clrBase), 2);
    UTF8String sClrModule = IntToHex(GetRValue(clrModule), 2) + IntToHex(GetGValue(clrModule), 2) + IntToHex(GetBValue(clrModule), 2);
    UTF8String svg =    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                        "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
                        "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 " + sSize + "\" stroke=\"none\">"
                        "<rect fill=\"#" + sClrBase + "\" width=\"100%\" height=\"100%\"/>"
                        "<path fill=\"#" + sClrModule + "\" d=\"";
    for (int y = 0; y < size; ++y)
        for (int x = 0; x < size; ++x)
            if (QRCodeEnc::GetModule(&qrcode[0], x, y))
                svg += L" M" + IntToStr((int)sizeMargin + x) + L"," + IntToStr((int)sizeMargin + y) + L"h1v1h-1z";
    svg += "\"/></svg>";
    return svg;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
 
TFont* EAN13Font = new TFont();
//---------------------------------------------------------------------------
 
String __fastcall EAN13IntToStr (__int64 num12Digit)
{
    String result;
    AnsiString s = StringOfChar('0', sizeof(EAN13Str));
    EAN13Str* ean13Str = (EAN13Str*)s.c_str();
    if (EAN13_NumToStr(num12Digit, *ean13Str))
        result = s;
    return result;
}
//---------------------------------------------------------------------------
 
bool __fastcall EAN13StrToInt (const String &strEAN13, __int64 &numEAN13)
{
    bool result = strEAN13.Length() == (int)sizeof(EAN13Str);
    if (result)
    {
        AnsiString s = strEAN13;
        EAN13Str* ean13Str = (EAN13Str*)s.c_str();
        result = EAN13_ValidateStr(*ean13Str) && TryStrToInt64(strEAN13, numEAN13);
    }
    return result;
}
//---------------------------------------------------------------------------
 
TBytes __fastcall EAN13Encode (String strEAN13)
{
    TBytes arrEAN13;
    if (strEAN13.Length() == (int)sizeof(EAN13Str))
    {
        AnsiString s = strEAN13;
        EAN13Str* ean13Str = (EAN13Str*)s.c_str();
        arrEAN13.Length = sizeof(EAN13);
        EAN13* ean13 = (EAN13*)&arrEAN13[0];
        if (!EAN13_EncodeStr(*ean13Str, *ean13))
            arrEAN13.Length = 0;
    }
    return arrEAN13;
}
//---------------------------------------------------------------------------
 
Graphics::TBitmap* __fastcall EAN13GetBMP (TBytes ean13, String ean13Num, TColor clrBase, TColor clrLine, size_t sizePxLine, float height, size_t sizePxMargin)
{
    Graphics::TBitmap* bmp = NULL;
    if (ean13.Length == (int)sizeof(EAN13)) // 95
    {
        bmp = new Graphics::TBitmap();
        try
        {
            int w = sizePxLine * ean13.Length;
            int h = w * height;
            TRect rect;
            int digitWidth = sizePxLine * 7;
            int numRectWidth = digitWidth * 6;
            int numFirstWidth = 0;
            int fontHeight = 0;
 
            ean13Num = Trim(ean13Num);
            String numFirst, numLeft, numRight;
 
            if (!ean13Num.IsEmpty() && ean13Num.Length() < 13)
                ean13Num = StringOfChar('0', 13 - ean13Num.Length()) + ean13Num;
            __int64 num;
            if (ean13Num.Length() == 13 && TryStrToInt64(ean13Num, num) && num >= 0)
            {
                // F LLLLLL RRRRRR
                if (ean13Num[1] != '0')
                    numFirst = ean13Num.SubString(1, 1);
                numLeft = ean13Num.SubString(2, 6);
                numRight = ean13Num.SubString(8, 6);
 
                int curLeftWidth = 0, curRightWidth = 0;
                int curFontHeight;
                if (EAN13Font)
                    bmp->Canvas->Font->Assign(EAN13Font);
                bmp->Canvas->Font->Height = 1;
                do
                {
                    fontHeight = bmp->Canvas->Font->Height;
                    curFontHeight = fontHeight + 1;
                    bmp->Canvas->Font->Height = curFontHeight;
                    SetRect(&rect, 0, 0, 0, 0);
                    DrawText(bmp->Canvas->Handle, numLeft.c_str(), numLeft.Length(), &rect, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
                    curLeftWidth = rect.Width();
                    SetRect(&rect, 0, 0, 0, 0);
                    DrawText(bmp->Canvas->Handle, numRight.c_str(), numRight.Length(), &rect, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
                    curRightWidth = rect.Width();
                }
                while (curLeftWidth < numRectWidth && curRightWidth < numRectWidth);
                bmp->Canvas->Font->Height = fontHeight;
 
                if (!numFirst.IsEmpty())
                {
                    SetRect(&rect, 0, 0, 0, 0);
                    DrawText(bmp->Canvas->Handle, numFirst.c_str(), numFirst.Length(), &rect, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
                    numFirstWidth = rect.Width() + sizePxLine * 2;
                }
            }
 
            bmp->SetSize(0, 0);
            bmp->Canvas->Brush->Color = clrBase;
            bmp->SetSize(sizePxMargin * 2 + numFirstWidth + w, sizePxMargin * 2 + h - fontHeight / 2 + fontHeight);
 
            bmp->Canvas->Brush->Color = clrLine;
            SetRect(&rect, sizePxMargin + numFirstWidth, sizePxMargin, sizePxMargin + numFirstWidth + sizePxLine, sizePxMargin + h);
            for (int x = 0; x < ean13.Length; ++x)
            {
                if (ean13[x])
                    bmp->Canvas->FillRect(rect);
                OffsetRect(rect, rect.Width(), 0);
            }
 
            if (!numLeft.IsEmpty() && !numRight.IsEmpty())
            {
                bmp->Canvas->Brush->Color = clrBase;
                bmp->Canvas->Font->Color = clrLine;
 
                if (!numFirst.IsEmpty())
                {
                    SetRect(&rect, sizePxMargin, sizePxMargin + h - bmp->Canvas->Font->Height / 2, sizePxMargin + numFirstWidth, sizePxMargin + h - bmp->Canvas->Font->Height / 2 + bmp->Canvas->Font->Height);
                    DrawText(bmp->Canvas->Handle, numFirst.c_str(), numFirst.Length(), &rect, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
                }
 
                SetRect(&rect, sizePxMargin + numFirstWidth + sizePxLine * 3, sizePxMargin + h - bmp->Canvas->Font->Height / 2, sizePxMargin + numFirstWidth + sizePxLine * 3 + numRectWidth, sizePxMargin + h - bmp->Canvas->Font->Height / 2 + bmp->Canvas->Font->Height);
                bmp->Canvas->FillRect(rect);
                DrawText(bmp->Canvas->Handle, numLeft.c_str(), numLeft.Length(), &rect, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
                OffsetRect(&rect, rect.Width() + sizePxLine * 5, 0);
                bmp->Canvas->FillRect(rect);
                DrawText(bmp->Canvas->Handle, numRight.c_str(), numRight.Length(), &rect, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP);
            }
        }
        catch (...)
        {
            delete bmp;
            bmp = NULL;
        }
    }
    return bmp;
}
//---------------------------------------------------------------------------
 
UTF8String __fastcall EAN13GetSVG (TBytes ean13, String ean13Num, TColor clrBase, TColor clrLine, float height, size_t sizeMargin)
{
    UTF8String svg;
    int w = ean13.Length;
    if (w == (int)sizeof(EAN13)) // 95
    {
        int h = w * height;
        int fontSize = 0;
        int numFirstWidth = 0;
 
        String numFirst, numLeft, numRight;
 
        if (!ean13Num.IsEmpty() && ean13Num.Length() < 13)
            ean13Num = StringOfChar('0', 13 - ean13Num.Length()) + ean13Num;
        __int64 num;
        if (ean13Num.Length() == 13 && TryStrToInt64(ean13Num, num) && num >= 0)
        {
            fontSize = 12;
            // F LLLLLL RRRRRR
            if (ean13Num[1] != '0')
            {
                numFirst = ean13Num.SubString(1, 1);
                numFirstWidth = fontSize / 2;
            }
            numLeft = ean13Num.SubString(2, 6);
            numRight = ean13Num.SubString(8, 6);
        }
 
        UTF8String sSize = IntToStr((int)sizeMargin * 2 + numFirstWidth + w) + L" " + IntToStr((int)sizeMargin * 2 + h + fontSize / 2);
        clrBase = (Graphics::TColor)ColorToRGB(clrBase);
        clrLine = (Graphics::TColor)ColorToRGB(clrLine);
        UTF8String sClrBase = IntToHex(GetRValue(clrBase), 2) + IntToHex(GetGValue(clrBase), 2) + IntToHex(GetBValue(clrBase), 2);
        UTF8String sClrLine = IntToHex(GetRValue(clrLine), 2) + IntToHex(GetGValue(clrLine), 2) + IntToHex(GetBValue(clrLine), 2);
        svg =   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
                "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 " + sSize + "\" stroke=\"none\">"
                "<rect fill=\"#" + sClrBase + "\" width=\"100%\" height=\"100%\"/>"
                "<path fill=\"#" + sClrLine + "\" d=\"";
 
        int p = 0;
        bool guardLine;
        for (int x = 0; x < w; ++x)
        {
            if (ean13[x])
                ++p;
            else if (p)
            {
                guardLine = x <= 3 || (x >= 46 && x <= 50) || x >= 93;
                svg += L" M" + IntToStr((int)sizeMargin + numFirstWidth + x - p) + L"," + IntToStr((int)sizeMargin) + L"h" + IntToStr(p) + L"v" + IntToStr(h - !guardLine * fontSize / 2) + L"h-" + IntToStr(p) + L"z";
                p = 0;
            }
        }
        if (p)
            svg += L" M" + IntToStr((int)sizeMargin + numFirstWidth + w - p) + L"," + IntToStr((int)sizeMargin) + L"h" + IntToStr(p) + L"v" + IntToStr(h) + L"h-" + IntToStr(p) + L"z";
        svg += "\"/>";
 
        if (fontSize)
        {
            UTF8String sTextAttr =  " font-family=\"Arial, Helvetica, sans-serif\""
                                    " dominant-baseline=\"central\""
                                    " fill=\"#" + sClrLine + "\"";
            sTextAttr += L" font-size=\"" + IntToStr(fontSize) + L"px\""
                         L" y=\"" + IntToStr((int)sizeMargin + h) + L"\"";
            if (numFirstWidth)
            {
                svg += "<text" + sTextAttr; svg += L" x=\"" + IntToStr((int)sizeMargin + numFirstWidth - 1) + L"\" text-anchor=\"end\">" + numFirst + L"</text>";
            }
            svg += "<text" + sTextAttr; svg += L" x=\"" + IntToStr((int)sizeMargin + numFirstWidth + 3 + 7 * 6 / 2            ) + L"\" text-anchor=\"middle\">" + numLeft  + L"</text>";
            svg += "<text" + sTextAttr; svg += L" x=\"" + IntToStr((int)sizeMargin + numFirstWidth + 3 + 7 * 6 + 5 + 7 * 6 / 2) + L"\" text-anchor=\"middle\">" + numRight + L"</text>";
        }
 
        svg += "</svg>";
    }
    return svg;
}
//---------------------------------------------------------------------------
 
} //namespace Barcode
//---------------------------------------------------------------------------
Здесь функция CheckIfChangeModeOpimized отвечает за оптимизацию сегментирования текста. Потом выполняется ещё одна оптимизация сегментов (в функции QRCodeEncode под комментом Another segment optimization). Получить такую же картинку QR-кода мне не удалось, т. к. данный код оптимизирует сегментацию ещё больше (на приведённом тексте на 10 бит короче, чем в ByteScout BarCode Generator).
0
0 / 0 / 0
Регистрация: 18.01.2019
Сообщений: 13
28.06.2024, 14:47
Цитата Сообщение от LBin Посмотреть сообщение
но и так же подготовить текст для кодирования
Что это значит – подготовить текст для кодирования?

Мы на самом деле больше года бъёмся над генерацией QR под сканер Honeywell. Не желает читать ни в какую. Наша рабочая прога BarTender. Кроме неё перепробовали ещё целую кучу доступного софта – тоже без результата.
Но конкуренты как-то генерят читаемые коды в приложении TFORMer, которую нигде сейчас не скачать и не купить.

Но мы пробовали генерить в её (TFORMer) демонстрационной версии при разных управляющих настройках – получить желаемую картинку тоже не удалось...

Может быть подбросите идею для решения?

PS. Во вложении код от конкурентов, который нужно получить.
Миниатюры
QR код всегда разный  
0
Модератор
Эксперт Java
 Аватар для alecss131
2863 / 1369 / 409
Регистрация: 11.08.2017
Сообщений: 4,392
Записей в блоге: 2
28.06.2024, 15:44
Цитата Сообщение от cmyk69 Посмотреть сообщение
Что это значит – подготовить текст для кодирования?
Вы с процедурой генерации QR кодов ознакомились? Они могут кодировать текст несколькими способами. Первый как текст и второй текст в байты а потом в код, при переводе в байты можно выбрать любую кодировку.
Символы кирилица или латиница?
У кодов существует 4 уровня коррекции ошибок и 40 версий самого кода, версия влияет на количество данных которые может вместить код. Итого в результате аж 160 вариантов самого кода, а так же несколько способов кодирования самих данных.
Но тут код сам маленький и версии в нем похоже нету, значит тут возможно 6 вариантов версий

Добавлено через 27 секунд
Вот например хорошая статья по генерации кода
1
0 / 0 / 0
Регистрация: 18.01.2019
Сообщений: 13
28.06.2024, 16:31
Коррекция – М (100%), код -24х24.
Это выяснить было самое лёгкое.

Но, всё равно, не генерится то, что нужно.

Добавлено через 44 секунды
100% – это значит, что сто-процентная уверенность в этом уровне.
0
Модератор
Эксперт Java
 Аватар для alecss131
2863 / 1369 / 409
Регистрация: 11.08.2017
Сообщений: 4,392
Записей в блоге: 2
28.06.2024, 22:10
Долго думал и сейчас подтверждаю свои догадки. Теперь подробнее
Цитата Сообщение от cmyk69 Посмотреть сообщение
Во вложении код от конкурентов, который нужно получить
Нашел сервис который показывает RAW дату, что очень помогло.
У вас данные в коде вот такие КСН-У-К-0011904001, сервис показал байты в коде вот так
Code
1
2
40 dd 09 ad 0a 1d 09 d2 dd 0a 32 dd 09 a2 d1 02
80 12 f9 90 10 ec 11 ec 11 ec 11 ec
Вот эта часть КСН-У-К- в UTF8 выглядит вот так D0 9A D0 A1 D0 9D 2D D0 A3 2D D0 9A 2D, в начале 40 D первые 4 бита имеют значение 4 (0b0100), что означает побайтовое кодирование, а оставшиеся байты образуют число 13, что совпадает с количеством символов в utf8 представлении фрагмента (судя по таблице 8 бит на байтовое кодиравиние у версий 1-9)
Идем дальше. Следующие 4 бита это число 1 (0b0001) цифровое кодирование. У версий 1-9 и цифрового кодирования длина занимает 10 бит, что как раз совпадает 10.
Этот тип кодирования требует 10 бит на 3 символа. Вся последовательность символов разбивается на группы по 3 цифры, и каждая группа (трёхзначное число) переводится в 10-битное двоичное число и добавляется к последовательности бит. Если общее количество символов не кратно 3, то если в конце остаётся 2 символа, полученное двузначное число кодируется 7 битами, а если 1 символ, то 4 битами.
В нашем случае 0011904001, делаем по инструкции. 001 - 190 - 400 - 1, что кодируется вот так 0000000001 - 0010111110 - 0110010000 - 0001, перегруппируем по 8 бит 00000000 - 01001011 - 11100110 - 01000000 - 01. В декодированных байтах это 80 12 F9 90 10, за исключением первых 2 бит. Далее 4 бита дополнены нулями до кратного 8 и после 7 байт неизвестного наполнения EC 11 EC 11 EC 11 EC, которое не показывают другие расшифровщики, хотя возможно мусор или ошибка расшифровки, но вот что здесь используется смешанное кодирование это 100%.
0
Заблокирован
29.06.2024, 21:39
Привет.
Извиняюсь, что пишу без цитирования и форматирования, т. К пишу с телефона - неудобно.
Подготовить текст - это подготовить данные для кодирования в Qr, разбить на сегменты. Это имеет смысл для разработчиков ПО, генерирующего qr, не для пользователей такого ПО.
У меня получился такой же рисунок матрицы qr кода, который вы приложили, с такими параметрами: версия 2, уровень коррекции ошибок medium 15%, маска 1.

Нет сейчас возможности посмотреть, как алгоритм сегментирует данные, но никакого особо хитрого разбития на сегменты здесь нет, текст простой.
0
Заблокирован
29.06.2024, 21:50
Посмотрите в интернетах, как определять маску и уровень коррекции в qr, эти данные находятся в матрице ниже верхнего левого настроечного узора (квадрата) и правее нижнего. Если ваше ПО не позволяет задать маску, то нужно искать то ПО, которое позволяет. Маску ПО обычно не позволяет задать, т к она выбирается автоматически на основе т н штрафных баллов. Но даже если ПО позволит задать маску, то 100% оно не позволит управлять сегментацией, поэтому на сложных текстах такой же узор матрицы сложно получить.
0
0 / 0 / 0
Регистрация: 18.01.2019
Сообщений: 13
01.07.2024, 10:50
Цитата Сообщение от LBin Посмотреть сообщение
У меня получился такой же рисунок матрицы qr кода, который вы приложили, с такими параметрами: версия 2, уровень коррекции ошибок medium 15%, маска 1.
Прилагаю QR с такими же параметрами, как и у вас: " версия 2, уровень коррекции ошибок medium 15%, маска 1"
Как видите, он совершенно иной, нежели получился у вас.

Там у нас, кстати, ещё куча кодировок разных (см. вложение), половина из которых выдаёт ошибку, а другая половина меняет внешний вид QR, но искомый, увы, никак не получается.

Скриншоты.
Миниатюры
QR код всегда разный   QR код всегда разный  
0
Заблокирован
01.07.2024, 11:42
Досконально могу посмотреть только завтра, но на первый взгляд вот что: кодировка должна быть utf-8. Покажите выпадающий список "режим". Скорее всего, не двоичный должен быть.
0
0 / 0 / 0
Регистрация: 18.01.2019
Сообщений: 13
01.07.2024, 12:11
Тоже думали, что юникод поначалу, но тоже не работает. Все имеющиеся перебором меняли – результат ноль.

По этой информации в коде (КСН-У...) только двоичный режим подходит. По остальным ошибку выдаёт, из-за кирилицы, наверное
Миниатюры
QR код всегда разный   QR код всегда разный  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.07.2024, 12:11
Помогаю со студенческими работами здесь

Тот же код - разный результат
Форумчане! Чем объяснить разницу в аутпуте: две while - одна copy pasted с другой - но в одной - при подсчете миль - нужно добавить 1 чтобы...

Разный код страницы на разных компьютерах
Добрый день! В HTML разбираюсь на очень слабом уровне, только в рамках программирования VBA с использованием библиотек Появилась...

с хабра и мой код дают разный результат. why
здравствуйте, ради обучения решил сделать проверку во время компиляции на наличие в классе функции, возвращающей void и принимающей int......

Почему html код сайта разный в разных браузерах?
Всем привет! Такой вопрос: почему в хроме код страницы один, а который получаю в делфи - другой? Пробовал разными методами- результат один....

Как выполнять разный HTML код, относительно размера экрана?
Здравствуйте. При разном размере экрана необходимо соблюдать разный размер вставляемой яндекс карты. Карта вставляется скриптом, без...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
BOINC: 22 года — и всё ещё работает
Programma_Boinc 12.03.2026
BOINC: 22 года — и всё ещё работает Дэвид Андерсон написал ретроспективу. Кратко: в 2001 году он ушёл из United Devices, где был CTO, и за несколько месяцев написал ядро BOINC — клиент, сервер,. . .
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru