/*
* QR Code generator library - Optional advanced logic (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
package io.nayuki.qrcodegen;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import io.nayuki.qrcodegen.QrSegment.Mode;
/**
* Splits text into optimal segments and encodes kanji segments.
* Provides static functions only; not instantiable.
* @see QrSegment
* @see QrCode
*/
public final class QrSegmentAdvanced {
/*---- Optimal list of segments encoder ----*/
/**
* Returns a list of zero or more segments to represent the specified Unicode text string.
* The resulting list optimally minimizes the total encoded bit length, subjected to the constraints
* in the specified {error correction level, minimum version number, maximum version number}.
* <p>This function can utilize all four text encoding modes: numeric, alphanumeric, byte (UTF-8),
* and kanji. This can be considered as a sophisticated but slower replacement for {@link
* QrSegment#makeSegments(CharSequence)}. This requires more input parameters because it searches a
* range of versions, like {@link QrCode#encodeSegments(List,QrCode.Ecc,int,int,int,boolean)}.</p>
* @param text the text to be encoded (not {@code null}), which can be any Unicode string
* @param ecl the error correction level to use (not {@code null})
* @param minVersion the minimum allowed version of the QR Code (at least 1)
* @param maxVersion the maximum allowed version of the QR Code (at most 40)
* @return a new mutable list (not {@code null}) of segments (not {@code null})
* containing the text, minimizing the bit length with respect to the constraints
* @throws NullPointerException if the text or error correction level is {@code null}
* @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated
* @throws DataTooLongException if the text fails to fit in the maxVersion QR Code at the ECL
*/
public static List<QrSegment> makeSegmentsOptimally(CharSequence text, QrCode.Ecc ecl, int minVersion, int maxVersion) {
// Check arguments
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
throw new IllegalArgumentException("Invalid value");
// Iterate through version numbers, and make tentative segments
List<QrSegment> segs = null;
int[] codePoints = toCodePoints(text);
for (int version = minVersion; ; version++) {
if (version == minVersion || version == 10 || version == 27)
segs = makeSegmentsOptimally(codePoints, version);
assert segs != null;
// Check if the segments fit
int dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
int dataUsedBits = QrSegment.getTotalBits(segs, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
return segs; // This version number is found to be suitable
if (version >= maxVersion) { // All versions in the range could not fit the given text
String msg = "Segment too long";
if (dataUsedBits != -1)
msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
throw new DataTooLongException(msg);
}
}
}
// Returns a new list of segments that is optimal for the given text at the given version number.
private static List<QrSegment> makeSegmentsOptimally(int[] codePoints, int version) {
if (codePoints.length == 0)
return new ArrayList<>();
Mode[] charModes = computeCharacterModes(codePoints, version);
return splitIntoSegments(codePoints, charModes);
}
// Returns a new array representing the optimal mode per code point based on the given text and version.
private static Mode[] computeCharacterModes(int[] codePoints, int version) {
if (codePoints.length == 0)
throw new IllegalArgumentException();
if (codePoints.length > 7089) // Upper bound is the number of characters that fit in QR Code version 40, low error correction, numeric mode
throw new DataTooLongException("String too long");
final Mode[] modeTypes = {Mode.BYTE, Mode.ALPHANUMERIC, Mode.NUMERIC, Mode.KANJI}; // Do not modify
final int numModes = modeTypes.length;
// Segment header sizes, measured in 1/6 bits
final int[] headCosts = new int[numModes];
for (int i = 0; i < numModes; i++) {
headCosts[i] = (4 + modeTypes[i].numCharCountBits(version)) * 6;
assert 0 <= headCosts[i] && headCosts[i] <= (4 + 16) * 6;
}
// charModes[i][j] represents the mode to encode the code point at
// index i such that the final segment ends in modeTypes[j] and the
// total number of bits is minimized over all possible choices
Mode[][] charModes = new Mode[codePoints.length][numModes];
// At the beginning of each iteration of the loop below,
// prevCosts[j] is the exact minimum number of 1/6 bits needed to
// encode the entire string prefix of length i, and end in modeTypes[j]
int[] prevCosts = headCosts.clone();
// Calculate costs using dynamic programming
for (int i = 0; i < codePoints.length; i++) {
int c = codePoints[i];
int[] curCosts = new int[numModes];
{ // Always extend a byte mode segment
curCosts[0] = prevCosts[0] + countUtf8Bytes(c) * 8 * 6;
charModes[i][0] = modeTypes[0];
}
// Extend a segment if possible
if (QrSegment.ALPHANUMERIC_CHARSET.indexOf(c) != -1) { // Is alphanumeric
curCosts[1] = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
charModes[i][1] = modeTypes[1];
}
if ('0' <= c && c <= '9') { // Is numeric
curCosts[2] = prevCosts[2] + 20; // 3.33 bits per digit
charModes[i][2] = modeTypes[2];
}
if (isKanji(c)) {
curCosts[3] = prevCosts[3] + 78; // 13 bits per Shift JIS char
charModes[i][3] = modeTypes[3];
}
// Start new segment at the end to switch modes
for (int j = 0; j < numModes; j++) { // To mode
for (int k = 0; k < numModes; k++) { // From mode
int newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
if (charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j])) {
curCosts[j] = newCost;
charModes[i][j] = modeTypes[k];
}
}
}
// A non-tight upper bound is when each of 7089 characters switches to
// byte mode (4-bit header + 16-bit count) and requires 4 bytes in UTF-8
for (int cost : curCosts)
assert 0 <= cost && cost <= (4 + 16 + 32) * 6 * 7089;
prevCosts = curCosts;
}
// Find optimal ending mode
Mode curMode = null;
for (int i = 0, minCost = 0; i < numModes; i++) {
if (curMode == null || prevCosts[i] < minCost) {
minCost = prevCosts[i];
curMode = modeTy
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
QR 二维码生成程序,支持多种语言 c/c++/java/python/rust Introduction ------------ This project aims to be the best, clearest QR Code generator library in multiple languages. The primary goals are flexible options and absolute correctness. Secondary goals are compact implementation size and good documentation comments.
资源推荐
资源详情
资源评论
收起资源包目录
QR-Code-generator-master.zip (52个子文件)
QR-Code-generator-master
typescript-javascript
qrcodegen-input-demo.html 6KB
qrcodegen-output-demo.html 2KB
qrcodegen-output-demo.ts 11KB
Readme.markdown 2KB
qrcodegen.ts 40KB
qrcodegen-input-demo.ts 9KB
build.sh 1KB
rust
Cargo.toml 426B
src
lib.rs 45KB
examples
qrcodegen-demo.rs 8KB
Readme.markdown 2KB
rust-no-heap
Cargo.toml 434B
src
lib.rs 53KB
examples
qrcodegen-demo.rs 12KB
Readme.markdown 3KB
java
pom.xml 4KB
src
main
java
module-info.java 1KB
io
nayuki
qrcodegen
QrSegmentAdvanced.java 35KB
BitBuffer.java 4KB
DataTooLongException.java 3KB
QrSegment.java 12KB
package-info.java 3KB
QrCode.java 35KB
Readme.markdown 3KB
QrCodeGeneratorDemo.java 12KB
c
Makefile 3KB
Readme.markdown 3KB
qrcodegen.c 41KB
qrcodegen.h 17KB
qrcodegen-test.c 29KB
qrcodegen-demo.c 12KB
Readme.markdown 4KB
java-fast
Readme.markdown 3KB
io
nayuki
fastqrcodegen
QrSegmentAdvanced.java 34KB
QrTemplate.java 10KB
Memoizer.java 3KB
BitBuffer.java 4KB
ReedSolomonGenerator.java 4KB
QrCodeGeneratorDemo.java 12KB
DataTooLongException.java 3KB
QrSegment.java 12KB
package-info.java 3KB
QrCode.java 26KB
python
qrcodegen.py 38KB
setup.py 4KB
qrcodegen-demo.py 8KB
Readme.markdown 2KB
cpp
Makefile 2KB
QrCodeGeneratorDemo.cpp 9KB
Readme.markdown 2KB
qrcodegen.hpp 20KB
qrcodegen.cpp 27KB
共 52 条
- 1
资源评论
GoldKey
- 粉丝: 8
- 资源: 23
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功