mmask.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * qrencode - QR Code encoder
  3. *
  4. * Masking for Micro QR Code.
  5. * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #if HAVE_CONFIG_H
  22. # include "config.h"
  23. #endif
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <limits.h>
  27. #include <errno.h>
  28. #include "qrencode.h"
  29. #include "mqrspec.h"
  30. #include "mmask.h"
  31. #define STATIC_IN_RELEASE
  32. STATIC_IN_RELEASE void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level)
  33. {
  34. unsigned int format;
  35. unsigned char v;
  36. int i;
  37. format = MQRspec_getFormatInfo(mask, version, level);
  38. for(i = 0; i < 8; i++) {
  39. v = 0x84 | (format & 1);
  40. frame[width * (i + 1) + 8] = v;
  41. format = format >> 1;
  42. }
  43. for(i = 0; i < 7; i++) {
  44. v = 0x84 | (format & 1);
  45. frame[width * 8 + 7 - i] = v;
  46. format = format >> 1;
  47. }
  48. }
  49. #define MASKMAKER(__exp__) \
  50. int x, y;\
  51. \
  52. for(y = 0; y < width; y++) {\
  53. for(x = 0; x < width; x++) {\
  54. if(*s & 0x80) {\
  55. *d = *s;\
  56. } else {\
  57. *d = *s ^ ((__exp__) == 0);\
  58. }\
  59. s++; d++;\
  60. }\
  61. }
  62. static void Mask_mask0(int width, const unsigned char *s, unsigned char *d)
  63. {
  64. MASKMAKER(y&1)
  65. }
  66. static void Mask_mask1(int width, const unsigned char *s, unsigned char *d)
  67. {
  68. MASKMAKER(((y/2)+(x/3))&1)
  69. }
  70. static void Mask_mask2(int width, const unsigned char *s, unsigned char *d)
  71. {
  72. MASKMAKER((((x*y)&1)+(x*y)%3)&1)
  73. }
  74. static void Mask_mask3(int width, const unsigned char *s, unsigned char *d)
  75. {
  76. MASKMAKER((((x+y)&1)+((x*y)%3))&1)
  77. }
  78. #define maskNum (4)
  79. typedef void MaskMaker(int, const unsigned char *, unsigned char *);
  80. static MaskMaker *maskMakers[maskNum] = {
  81. Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3
  82. };
  83. #ifdef WITH_TESTS
  84. unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask)
  85. {
  86. unsigned char *masked;
  87. masked = (unsigned char *)malloc((size_t)(width * width));
  88. if(masked == NULL) return NULL;
  89. maskMakers[mask](width, frame, masked);
  90. return masked;
  91. }
  92. #endif
  93. unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level)
  94. {
  95. unsigned char *masked;
  96. int width;
  97. if(mask < 0 || mask >= maskNum) {
  98. errno = EINVAL;
  99. return NULL;
  100. }
  101. width = MQRspec_getWidth(version);
  102. masked = (unsigned char *)malloc((size_t)(width * width));
  103. if(masked == NULL) return NULL;
  104. maskMakers[mask](width, frame, masked);
  105. MMask_writeFormatInformation(version, width, masked, mask, level);
  106. return masked;
  107. }
  108. STATIC_IN_RELEASE int MMask_evaluateSymbol(int width, unsigned char *frame)
  109. {
  110. int x, y;
  111. unsigned char *p;
  112. int sum1 = 0, sum2 = 0;
  113. p = frame + width * (width - 1);
  114. for(x = 1; x < width; x++) {
  115. sum1 += (p[x] & 1);
  116. }
  117. p = frame + width * 2 - 1;
  118. for(y = 1; y < width; y++) {
  119. sum2 += (*p & 1);
  120. p += width;
  121. }
  122. return (sum1 <= sum2)?(sum1 * 16 + sum2):(sum2 * 16 + sum1);
  123. }
  124. unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level)
  125. {
  126. int i;
  127. unsigned char *mask, *bestMask;
  128. int maxScore = 0;
  129. int score;
  130. int width;
  131. width = MQRspec_getWidth(version);
  132. mask = (unsigned char *)malloc((size_t)(width * width));
  133. if(mask == NULL) return NULL;
  134. bestMask = NULL;
  135. for(i = 0; i < maskNum; i++) {
  136. score = 0;
  137. maskMakers[i](width, frame, mask);
  138. MMask_writeFormatInformation(version, width, mask, i, level);
  139. score = MMask_evaluateSymbol(width, mask);
  140. if(score > maxScore) {
  141. maxScore = score;
  142. free(bestMask);
  143. bestMask = mask;
  144. mask = (unsigned char *)malloc((size_t)(width * width));
  145. if(mask == NULL) break;
  146. }
  147. }
  148. free(mask);
  149. return bestMask;
  150. }