From 9ba879aa77a14e6a3d42b59c670937eeb64c706e Mon Sep 17 00:00:00 2001 From: srowen Date: Sat, 15 May 2010 11:21:03 +0000 Subject: [PATCH] Move character encoding logic out to common, try again to improve its handling of UTF8 for Chinese market, per manufacturer request, added test cases git-svn-id: http://zxing.googlecode.com/svn/trunk@1364 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../com/google/zxing/common/StringUtils.java | 191 ++++++++++++++++++ .../decoder/DecodedBitStreamParser.java | 113 +---------- core/test/data/blackbox/qrcode-2/29.jpg | Bin 0 -> 3104 bytes core/test/data/blackbox/qrcode-2/29.txt | 3 + core/test/data/blackbox/qrcode-2/30.png | Bin 0 -> 1602 bytes core/test/data/blackbox/qrcode-2/30.txt | 1 + core/test/data/blackbox/qrcode-2/31.jpg | Bin 0 -> 27905 bytes core/test/data/blackbox/qrcode-2/31.txt | 1 + .../zxing/qrcode/QRCodeBlackBox2TestCase.java | 8 +- .../DecodedBitStreamParserTestCase.java | 5 +- 10 files changed, 206 insertions(+), 116 deletions(-) create mode 100644 core/src/com/google/zxing/common/StringUtils.java create mode 100644 core/test/data/blackbox/qrcode-2/29.jpg create mode 100644 core/test/data/blackbox/qrcode-2/29.txt create mode 100644 core/test/data/blackbox/qrcode-2/30.png create mode 100644 core/test/data/blackbox/qrcode-2/30.txt create mode 100644 core/test/data/blackbox/qrcode-2/31.jpg create mode 100644 core/test/data/blackbox/qrcode-2/31.txt diff --git a/core/src/com/google/zxing/common/StringUtils.java b/core/src/com/google/zxing/common/StringUtils.java new file mode 100644 index 00000000..d3a7c2b6 --- /dev/null +++ b/core/src/com/google/zxing/common/StringUtils.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.common; + +import java.util.Hashtable; + +import com.google.zxing.DecodeHintType; + +/** + * Common string-related functions. + * + * @author Sean Owen + */ +public final class StringUtils { + + private static final String PLATFORM_DEFAULT_ENCODING = + System.getProperty("file.encoding"); + public static final String SHIFT_JIS = "SJIS"; + private static final String EUC_JP = "EUC_JP"; + private static final String UTF8 = "UTF8"; + private static final String ISO88591 = "ISO8859_1"; + private static final boolean ASSUME_SHIFT_JIS = + SHIFT_JIS.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING) || + EUC_JP.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING); + + private StringUtils() {} + + /** + * @param bytes bytes encoding a string, whose encoding should be guessed + * @param hints decode hints if applicable + * @return name of guessed encoding; at the moment will only guess one of: + * {@link #SHIFT_JIS}, {@link #UTF8}, {@link #ISO88591}, or the platform + * default encoding if none of these can possibly be correct + */ + public static String guessEncoding(byte[] bytes, Hashtable hints) { + if (hints != null) { + String characterSet = (String) hints.get(DecodeHintType.CHARACTER_SET); + if (characterSet != null) { + return characterSet; + } + } + // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 + if (bytes.length > 3 && + bytes[0] == (byte) 0xEF && + bytes[1] == (byte) 0xBB && + bytes[2] == (byte) 0xBF) { + return UTF8; + } + // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, + // which should be by far the most common encodings. ISO-8859-1 + // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS + // uses this as a first byte of a two-byte character. If we see this + // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. + // If we see something else in that second byte, we'll make the risky guess + // that it's UTF-8. + int length = bytes.length; + boolean canBeISO88591 = true; + boolean canBeShiftJIS = true; + boolean canBeUTF8 = true; + int utf8BytesLeft = 0; + int maybeDoubleByteCount = 0; + int maybeSingleByteKatakanaCount = 0; + boolean sawLatin1Supplement = false; + boolean sawUTF8Start = false; + boolean lastWasPossibleDoubleByteStart = false; + + for (int i = 0; + i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); + i++) { + + int value = bytes[i] & 0xFF; + + // UTF-8 stuff + if (value >= 0x80 && value <= 0xBF) { + if (utf8BytesLeft > 0) { + utf8BytesLeft--; + } + } else { + if (utf8BytesLeft > 0) { + canBeUTF8 = false; + } + if (value >= 0xC0 && value <= 0xFD) { + sawUTF8Start = true; + int valueCopy = value; + while ((valueCopy & 0x40) != 0) { + utf8BytesLeft++; + valueCopy <<= 1; + } + } + } + + // ISO-8859-1 stuff + + if ((value == 0xC2 || value == 0xC3) && i < length - 1) { + // This is really a poor hack. The slightly more exotic characters people might want to put in + // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings + // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF]. + int nextValue = bytes[i + 1] & 0xFF; + if (nextValue <= 0xBF && + ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) { + sawLatin1Supplement = true; + } + } + if (value >= 0x7F && value <= 0x9F) { + canBeISO88591 = false; + } + + // Shift_JIS stuff + + if (value >= 0xA1 && value <= 0xDF) { + // count the number of characters that might be a Shift_JIS single-byte Katakana character + if (!lastWasPossibleDoubleByteStart) { + maybeSingleByteKatakanaCount++; + } + } + if (!lastWasPossibleDoubleByteStart && + ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) { + canBeShiftJIS = false; + } + if (((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF))) { + // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid + // second byte. + if (lastWasPossibleDoubleByteStart) { + // If we just checked this and the last byte for being a valid double-byte + // char, don't check starting on this byte. If this and the last byte + // formed a valid pair, then this shouldn't be checked to see if it starts + // a double byte pair of course. + lastWasPossibleDoubleByteStart = false; + } else { + // ... otherwise do check to see if this plus the next byte form a valid + // double byte pair encoding a character. + lastWasPossibleDoubleByteStart = true; + if (i >= bytes.length - 1) { + canBeShiftJIS = false; + } else { + int nextValue = bytes[i + 1] & 0xFF; + if (nextValue < 0x40 || nextValue > 0xFC) { + canBeShiftJIS = false; + } else { + maybeDoubleByteCount++; + } + // There is some conflicting information out there about which bytes can follow which in + // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice. + } + } + } else { + lastWasPossibleDoubleByteStart = false; + } + } + if (utf8BytesLeft > 0) { + canBeUTF8 = false; + } + + // Easy -- if assuming Shift_JIS and no evidence it can't be, done + if (canBeShiftJIS && ASSUME_SHIFT_JIS) { + return SHIFT_JIS; + } + if (canBeUTF8 && sawUTF8Start) { + return UTF8; + } + // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is: + // - If we saw + // - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or + // - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1), + // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS + if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) { + return SHIFT_JIS; + } + // Otherwise, we default to ISO-8859-1 unless we know it can't be + if (!sawLatin1Supplement && canBeISO88591) { + return ISO88591; + } + // Otherwise, we take a wild guess with platform encoding + return PLATFORM_DEFAULT_ENCODING; + } + +} diff --git a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java index 25907e3b..94325d3d 100644 --- a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java +++ b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java @@ -16,11 +16,11 @@ package com.google.zxing.qrcode.decoder; -import com.google.zxing.DecodeHintType; import com.google.zxing.FormatException; import com.google.zxing.common.BitSource; import com.google.zxing.common.CharacterSetECI; import com.google.zxing.common.DecoderResult; +import com.google.zxing.common.StringUtils; import java.io.UnsupportedEncodingException; import java.util.Hashtable; @@ -45,16 +45,6 @@ final class DecodedBitStreamParser { 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' }; - private static final String SHIFT_JIS = "SJIS"; - private static final String EUC_JP = "EUC_JP"; - private static final boolean ASSUME_SHIFT_JIS; - private static final String UTF8 = "UTF8"; - private static final String ISO88591 = "ISO8859_1"; - - static { - String platformDefault = System.getProperty("file.encoding"); - ASSUME_SHIFT_JIS = SHIFT_JIS.equalsIgnoreCase(platformDefault) || EUC_JP.equalsIgnoreCase(platformDefault); - } private DecodedBitStreamParser() { } @@ -140,7 +130,7 @@ final class DecodedBitStreamParser { } // Shift_JIS may not be supported in some environments: try { - result.append(new String(buffer, SHIFT_JIS)); + result.append(new String(buffer, StringUtils.SHIFT_JIS)); } catch (UnsupportedEncodingException uee) { throw FormatException.getFormatInstance(); } @@ -166,7 +156,7 @@ final class DecodedBitStreamParser { // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. - encoding = guessEncoding(readBytes, hints); + encoding = StringUtils.guessEncoding(readBytes, hints); } else { encoding = currentCharacterSetECI.getEncodingName(); } @@ -243,103 +233,6 @@ final class DecodedBitStreamParser { result.append(ALPHANUMERIC_CHARS[digitBits]); } } - - private static String guessEncoding(byte[] bytes, Hashtable hints) { - if (hints != null) { - String characterSet = (String) hints.get(DecodeHintType.CHARACTER_SET); - if (characterSet != null) { - return characterSet; - } - } - if (ASSUME_SHIFT_JIS) { - return SHIFT_JIS; - } - // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 - if (bytes.length > 3 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) { - return UTF8; - } - // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, - // which should be by far the most common encodings. ISO-8859-1 - // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS - // uses this as a first byte of a two-byte character. If we see this - // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. - // If we see something else in that second byte, we'll make the risky guess - // that it's UTF-8. - int length = bytes.length; - boolean canBeISO88591 = true; - boolean canBeShiftJIS = true; - int maybeDoubleByteCount = 0; - int maybeSingleByteKatakanaCount = 0; - boolean sawLatin1Supplement = false; - boolean lastWasPossibleDoubleByteStart = false; - for (int i = 0; i < length && (canBeISO88591 || canBeShiftJIS); i++) { - int value = bytes[i] & 0xFF; - if ((value == 0xC2 || value == 0xC3) && i < length - 1) { - // This is really a poor hack. The slightly more exotic characters people might want to put in - // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings - // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF]. - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue <= 0xBF && ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) { - sawLatin1Supplement = true; - } - } - if (value >= 0x7F && value <= 0x9F) { - canBeISO88591 = false; - } - if (value >= 0xA1 && value <= 0xDF) { - // count the number of characters that might be a Shift_JIS single-byte Katakana character - if (!lastWasPossibleDoubleByteStart) { - maybeSingleByteKatakanaCount++; - } - } - if (!lastWasPossibleDoubleByteStart && ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) { - canBeShiftJIS = false; - } - if (((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF))) { - // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid - // second byte. - if (lastWasPossibleDoubleByteStart) { - // If we just checked this and the last byte for being a valid double-byte - // char, don't check starting on this byte. If this and the last byte - // formed a valid pair, then this shouldn't be checked to see if it starts - // a double byte pair of course. - lastWasPossibleDoubleByteStart = false; - } else { - // ... otherwise do check to see if this plus the next byte form a valid - // double byte pair encoding a character. - lastWasPossibleDoubleByteStart = true; - if (i >= bytes.length - 1) { - canBeShiftJIS = false; - } else { - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue < 0x40 || nextValue > 0xFC) { - canBeShiftJIS = false; - } else { - maybeDoubleByteCount++; - } - // There is some conflicting information out there about which bytes can follow which in - // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice. - } - } - } else { - lastWasPossibleDoubleByteStart = false; - } - } - // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is: - // - If we saw - // - at least three byte that starts a double-byte value (bytes that are rare in ISO-8859-1), or - // - over 5% of bytes that could be single-byte Katakana (also rare in ISO-8859-1), - // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS - if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) { - return SHIFT_JIS; - } - // Otherwise, we default to ISO-8859-1 unless we know it can't be - if (!sawLatin1Supplement && canBeISO88591) { - return ISO88591; - } - // Otherwise, we take a wild guess with UTF-8 - return UTF8; - } private static int parseECIValue(BitSource bits) { int firstByte = bits.readBits(8); diff --git a/core/test/data/blackbox/qrcode-2/29.jpg b/core/test/data/blackbox/qrcode-2/29.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b4dc691060affbaaec2277e2a76cf94a7894d26 GIT binary patch literal 3104 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 literal 0 HcmV?d00001 diff --git a/core/test/data/blackbox/qrcode-2/29.txt b/core/test/data/blackbox/qrcode-2/29.txt new file mode 100644 index 00000000..87ad2998 --- /dev/null +++ b/core/test/data/blackbox/qrcode-2/29.txt @@ -0,0 +1,3 @@ +http://live.fdgm.jp/u/event/hype/hype_top.html + +MEBKM:TITLE:hypeモバイル;URL:http\://live.fdgm.jp/u/event/hype/hype_top.html;; \ No newline at end of file diff --git a/core/test/data/blackbox/qrcode-2/30.png b/core/test/data/blackbox/qrcode-2/30.png new file mode 100644 index 0000000000000000000000000000000000000000..f6407bd65246315f3f8e0f2d92c4e1798c9e45c2 GIT binary patch literal 1602 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 Nk%bxL@R)C}{{v9S4wwJ{ literal 0 HcmV?d00001 diff --git a/core/test/data/blackbox/qrcode-2/31.txt b/core/test/data/blackbox/qrcode-2/31.txt new file mode 100644 index 00000000..59d2e9da --- /dev/null +++ b/core/test/data/blackbox/qrcode-2/31.txt @@ -0,0 +1 @@ +今度のバージョンでは文章の暗号化ができます。 \ No newline at end of file diff --git a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java index b31caa4e..80bac2f7 100644 --- a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java +++ b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java @@ -27,10 +27,10 @@ public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase { public QRCodeBlackBox2TestCase() { super("test/data/blackbox/qrcode-2", new MultiFormatReader(), BarcodeFormat.QR_CODE); - addTest(21, 21, 0.0f); - addTest(18, 18, 90.0f); - addTest(20, 20, 180.0f); - addTest(18, 18, 270.0f); + addTest(23, 23, 0.0f); + addTest(21, 21, 90.0f); + addTest(23, 23, 180.0f); + addTest(20, 21, 270.0f); } } diff --git a/core/test/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParserTestCase.java b/core/test/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParserTestCase.java index ddd1052e..eabb134c 100644 --- a/core/test/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParserTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParserTestCase.java @@ -41,13 +41,14 @@ public final class DecodedBitStreamParserTestCase extends TestCase { public void testSimpleSJIS() throws Exception { BitSourceBuilder builder = new BitSourceBuilder(); builder.write(0x04, 4); // Byte mode - builder.write(0x03, 8); // 3 bytes + builder.write(0x04, 8); // 4 bytes builder.write(0xA1, 8); builder.write(0xA2, 8); builder.write(0xA3, 8); + builder.write(0xD0, 8); String result = DecodedBitStreamParser.decode(builder.toByteArray(), Version.getVersionForNumber(1), null, null).getText(); - assertEquals("\uff61\uff62\uff63", result); + assertEquals("\uff61\uff62\uff63\uff90", result); } public void testECI() throws Exception { -- 2.20.1