| /* |
| * qrencode - QR Code encoder |
| * |
| * Masking for Micro QR Code. |
| * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #if HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| #include <stdlib.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <errno.h> |
| |
| #include "qrencode.h" |
| #include "mqrspec.h" |
| #include "mmask.h" |
| |
| static void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level) |
| { |
| unsigned int format; |
| unsigned char v; |
| int i; |
| |
| format = MQRspec_getFormatInfo(mask, version, level); |
| |
| for(i=0; i<8; i++) { |
| v = 0x84 | (format & 1); |
| frame[width * (i + 1) + 8] = v; |
| format = format >> 1; |
| } |
| for(i=0; i<7; i++) { |
| v = 0x84 | (format & 1); |
| frame[width * 8 + 7 - i] = v; |
| format = format >> 1; |
| } |
| } |
| |
| #define MASKMAKER(__exp__) \ |
| int x, y;\ |
| \ |
| for(y=0; y<width; y++) {\ |
| for(x=0; x<width; x++) {\ |
| if(*s & 0x80) {\ |
| *d = *s;\ |
| } else {\ |
| *d = *s ^ ((__exp__) == 0);\ |
| }\ |
| s++; d++;\ |
| }\ |
| } |
| |
| static void Mask_mask0(int width, const unsigned char *s, unsigned char *d) |
| { |
| MASKMAKER(y&1) |
| } |
| |
| static void Mask_mask1(int width, const unsigned char *s, unsigned char *d) |
| { |
| MASKMAKER(((y/2)+(x/3))&1) |
| } |
| |
| static void Mask_mask2(int width, const unsigned char *s, unsigned char *d) |
| { |
| MASKMAKER((((x*y)&1)+(x*y)%3)&1) |
| } |
| |
| static void Mask_mask3(int width, const unsigned char *s, unsigned char *d) |
| { |
| MASKMAKER((((x+y)&1)+((x*y)%3))&1) |
| } |
| |
| #define maskNum (4) |
| typedef void MaskMaker(int, const unsigned char *, unsigned char *); |
| static MaskMaker *maskMakers[maskNum] = { |
| Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3 |
| }; |
| |
| #ifdef WITH_TESTS |
| unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask) |
| { |
| unsigned char *masked; |
| |
| masked = (unsigned char *)malloc(width * width); |
| if(masked == NULL) return NULL; |
| |
| maskMakers[mask](width, frame, masked); |
| |
| return masked; |
| } |
| #endif |
| |
| unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level) |
| { |
| unsigned char *masked; |
| int width; |
| |
| if(mask < 0 || mask >= maskNum) { |
| errno = EINVAL; |
| return NULL; |
| } |
| |
| width = MQRspec_getWidth(version); |
| masked = (unsigned char *)malloc(width * width); |
| if(masked == NULL) return NULL; |
| |
| maskMakers[mask](width, frame, masked); |
| MMask_writeFormatInformation(version, width, masked, mask, level); |
| |
| return masked; |
| } |
| |
| static int MMask_evaluateSymbol(int width, unsigned char *frame) |
| { |
| int x, y; |
| unsigned char *p; |
| int sum1 = 0, sum2 = 0; |
| |
| p = frame + width * (width - 1); |
| for(x=1; x<width; x++) { |
| sum1 += (p[x] & 1); |
| } |
| |
| p = frame + width * 2 - 1; |
| for(y=1; y<width; y++) { |
| sum2 += (*p & 1); |
| p += width; |
| } |
| |
| return (sum1 <= sum2)?(sum1 * 16 + sum2):(sum2 * 16 + sum1); |
| } |
| |
| unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level) |
| { |
| int i; |
| unsigned char *mask, *bestMask; |
| int maxScore = 0; |
| int score; |
| int width; |
| |
| width = MQRspec_getWidth(version); |
| |
| mask = (unsigned char *)malloc(width * width); |
| if(mask == NULL) return NULL; |
| bestMask = NULL; |
| |
| for(i=0; i<maskNum; i++) { |
| score = 0; |
| maskMakers[i](width, frame, mask); |
| MMask_writeFormatInformation(version, width, mask, i, level); |
| score = MMask_evaluateSymbol(width, mask); |
| if(score > maxScore) { |
| maxScore = score; |
| free(bestMask); |
| bestMask = mask; |
| mask = (unsigned char *)malloc(width * width); |
| if(mask == NULL) break; |
| } |
| } |
| free(mask); |
| return bestMask; |
| } |