
uk.org.okapibarcode.backend.Symbol Maven / Gradle / Ivy
Go to download
An open-source barcode generator written entirely in Java, supporting over 50 encoding standards including all ISO standards.
/*
* Copyright 2014 Robin Stuart
*
* 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 uk.org.okapibarcode.backend;
import static uk.org.okapibarcode.backend.HumanReadableLocation.BOTTOM;
import static uk.org.okapibarcode.backend.HumanReadableLocation.NONE;
import static uk.org.okapibarcode.backend.HumanReadableLocation.TOP;
import static uk.org.okapibarcode.util.Doubles.roughlyEqual;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
/**
* Generic barcode symbology class.
*
* TODO: Setting attributes like module width, font size, etc should probably throw
* an exception if set *after* encoding has already been completed.
*
* @author Robin Stuart
*/
public abstract class Symbol {
protected String content;
protected String readable = "";
protected String[] pattern;
protected int row_count = 0;
protected int[] row_height;
protected boolean debug = false;
protected String error_msg = "";
protected int symbol_height = 0;
protected int symbol_width = 0;
protected int default_height = 40;
protected int moduleWidth = 1;
protected String fontName = "Helvetica";
protected double fontSize = 8;
protected HumanReadableLocation humanReadableLocation = BOTTOM;
protected boolean readerInit;
protected String encodeInfo = "";
protected int eciMode = 3;
protected byte[] inputBytes;
protected DataType inputDataType = DataType.ECI;
public enum DataType {
UTF8, LATIN1, BINARY, GS1, HIBC, ECI
}
// TODO: These values to become accessible only to renderer
public ArrayList< Rectangle2D.Double > rectangles = new ArrayList<>();
public ArrayList< TextBox > texts = new ArrayList<>();
public ArrayList< Hexagon > hexagons = new ArrayList<>();
public ArrayList< Ellipse2D.Double > target = new ArrayList<>();
public Symbol() {
unsetReaderInit();
}
/**
* Sets the type of input data. This setting influences what
* pre-processing is done on data before encoding in the symbol.
* For example: for GS1
mode the AI data will be used to
* calculate the position of 'FNC1' characters.
* Valid values are:
*
* UTF8
(default) Unicode encoding
* LATIN1
ISO 8859-1 (Latin-1) encoding
* BINARY
Byte encoding mode
* GS1
Application Identifier and data pairs in "[AI]DATA" format
* HIBC
Health Industry Bar Code number (without check digit)
* ECI
Extended Channel Interpretations
*
* @param dataType A DataType
value which specifies the type of data
*/
public void setDataType(DataType dataType) {
inputDataType = dataType;
}
/**
* Prefixes symbol data with a "Reader Initialisation" or "Reader
* Programming" instruction.
*/
public final void setReaderInit() {
readerInit = true;
}
/**
* Removes "Reader Initialisation" or "Reader Programming" instruction
* from symbol data.
*/
public final void unsetReaderInit() {
readerInit = false;
}
/**
* Sets the default bar height for this symbol (default value is 40
).
*
* @param barHeight the default bar height for this symbol
*/
public void setBarHeight(int barHeight) {
this.default_height = barHeight;
}
/**
* Returns the default bar height for this symbol.
*
* @return the default bar height for this symbol
*/
public int getBarHeight() {
return default_height;
}
/**
* Sets the module width for this symbol (default value is 1
).
*
* @param moduleWidth the module width for this symbol
*/
public void setModuleWidth(int moduleWidth) {
this.moduleWidth = moduleWidth;
}
/**
* Returns the module width for this symbol.
*
* @return the module width for this symbol
*/
public int getModuleWidth() {
return moduleWidth;
}
/**
* Sets the name of the font to use to render the human-readable text (default value is Helvetica
).
*
* @param fontName the name of the font to use to render the human-readable text
*/
public void setFontName(String fontName) {
this.fontName = fontName;
}
/**
* Returns the name of the font to use to render the human-readable text.
*
* @return the name of the font to use to render the human-readable text
*/
public String getFontName() {
return fontName;
}
/**
* Sets the size of the font to use to render the human-readable text (default value is 8
).
*
* @param fontSize the size of the font to use to render the human-readable text
*/
public void setFontSize(double fontSize) {
this.fontSize = fontSize;
}
/**
* Returns the size of the font to use to render the human-readable text.
*
* @return the size of the font to use to render the human-readable text
*/
public double getFontSize() {
return fontSize;
}
/**
* Gets the width of the encoded symbol as a multiple of the
* x-dimension.
* @return an integer
specifying the width of the symbol
*/
public int getWidth() {
return symbol_width;
}
/**
* Gets a human readable summary of the decisions made by the encoder
* when creating a symbol.
* @return a String
containing encoding information
*/
public String getEncodeInfo() {
return encodeInfo;
}
/**
* Returns the height of the symbol, including the human-readable text, if any. This height is
* an approximation, since it is calculated without access to a font engine.
*
* @return the height of the symbol, including the human-readable text, if any
*/
public int getHeight() {
return symbol_height + getHumanReadableHeight();
}
/**
* Returns the height of the human-readable text, including the space between the text and other symbols.
* This height is an approximation, since it is calculated without access to a font engine.
*
* @return the height of the human-readable text
*/
public int getHumanReadableHeight() {
if (texts.isEmpty()) {
return 0;
} else {
return getTheoreticalHumanReadableHeight();
}
}
/**
* Returns the height of the human-readable text, assuming this symbol had human-readable text.
*
* @return the height of the human-readable text, assuming this symbol had human-readable text
*/
protected int getTheoreticalHumanReadableHeight() {
return (int) Math.ceil(fontSize * 1.2); // 0.2 space between bars and text
}
/**
* Sets the location of the human-readable text (default value is {@link HumanReadableLocation#BOTTOM}).
*
* @param humanReadableLocation the location of the human-readable text
*/
public void setHumanReadableLocation(HumanReadableLocation humanReadableLocation) {
this.humanReadableLocation = humanReadableLocation;
}
/**
* Returns the location of the human-readable text.
*
* @return the location of the human-readable text
*/
public HumanReadableLocation getHumanReadableLocation() {
return humanReadableLocation;
}
protected int positionOf(char thischar, char[] LookUp) {
int i, outval = 0;
for (i = 0; i < LookUp.length; i++) {
if (thischar == LookUp[i]) {
outval = i;
}
}
return outval;
}
protected String bin2pat(String bin) {
boolean black;
int i, l;
String pat = "";
black = true;
l = 0;
for (i = 0; i < bin.length(); i++) {
if (black) {
if (bin.charAt(i) == '1') {
l++;
} else {
black = false;
pat += (char)(l + '0');
l = 1;
}
} else {
if (bin.charAt(i) == '0') {
l++;
} else {
black = true;
pat += (char)(l + '0');
l = 1;
}
}
}
pat += (char)(l + '0');
return pat;
}
/**
* Set the data to be encoded. Input data will be assumed to be of
* the type set by setDataType
.
* @param input_data A String
containing the data to encode
* @throws OkapiException If no data or data is invalid
*/
public void setContent(String input_data) {
int i;
content = input_data; // default action
if (inputDataType == DataType.GS1) {
content = gs1SanityCheck(input_data);
}
if (inputDataType == DataType.GS1) {
readable = "";
for (i = 0; i < input_data.length(); i++) {
switch(input_data.charAt(i)) {
case '[': readable += '(';
break;
case ']': readable += ')';
break;
default: readable += input_data.charAt(i);
break;
}
}
}
if (inputDataType == DataType.HIBC) {
content = hibcProcess(input_data);
}
if (!content.isEmpty()) {
if (!encode()) {
throw new OkapiException(error_msg);
}
} else {
throw new OkapiException("No input data");
}
}
public String getContent() {
return content;
}
protected void eciProcess() {
int qmarksBefore, qmarksAfter;
int i;
qmarksBefore = 0;
for (i = 0; i < content.length(); i++) {
if (content.charAt(i) == '?') {
qmarksBefore++;
}
}
qmarksAfter = eciEncode("ISO8859_1");
if (qmarksAfter == qmarksBefore) {
eciMode = 3;
encodeInfo += "Encoding in ISO 8859-1 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_2");
if (qmarksAfter == qmarksBefore) {
eciMode = 4;
encodeInfo += "Encoding in ISO 8859-2 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_3");
if (qmarksAfter == qmarksBefore) {
eciMode = 5;
encodeInfo += "Encoding in ISO 8859-3 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_4");
if (qmarksAfter == qmarksBefore) {
eciMode = 6;
encodeInfo += "Encoding in ISO 8859-4 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_5");
if (qmarksAfter == qmarksBefore) {
eciMode = 7;
encodeInfo += "Encoding in ISO 8859-5 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_6");
if (qmarksAfter == qmarksBefore) {
eciMode = 8;
encodeInfo += "Encoding in ISO 8859-6 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_7");
if (qmarksAfter == qmarksBefore) {
eciMode = 9;
encodeInfo += "Encoding in ISO 8859-7 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_8");
if (qmarksAfter == qmarksBefore) {
eciMode = 10;
encodeInfo += "Encoding in ISO 8859-8 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_9");
if (qmarksAfter == qmarksBefore) {
eciMode = 11;
encodeInfo += "Encoding in ISO 8859-9 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_10");
if (qmarksAfter == qmarksBefore) {
eciMode = 12;
encodeInfo += "Encoding in ISO 8859-10 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_11");
if (qmarksAfter == qmarksBefore) {
eciMode = 13;
encodeInfo += "Encoding in ISO 8859-11 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_13");
if (qmarksAfter == qmarksBefore) {
eciMode = 15;
encodeInfo += "Encoding in ISO 8859-13 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_14");
if (qmarksAfter == qmarksBefore) {
eciMode = 16;
encodeInfo += "Encoding in ISO 8859-14 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_15");
if (qmarksAfter == qmarksBefore) {
eciMode = 17;
encodeInfo += "Encoding in ISO 8859-15 character set\n";
return;
}
qmarksAfter = eciEncode("ISO8859_16");
if (qmarksAfter == qmarksBefore) {
eciMode = 18;
encodeInfo += "Encoding in ISO 8859-16 character set\n";
return;
}
qmarksAfter = eciEncode("Windows_1250");
if (qmarksAfter == qmarksBefore) {
eciMode = 21;
encodeInfo += "Encoding in Windows-1250 character set\n";
return;
}
qmarksAfter = eciEncode("Windows_1251");
if (qmarksAfter == qmarksBefore) {
eciMode = 22;
encodeInfo += "Encoding in Windows-1251 character set\n";
return;
}
qmarksAfter = eciEncode("Windows_1252");
if (qmarksAfter == qmarksBefore) {
eciMode = 23;
encodeInfo += "Encoding in Windows-1252 character set\n";
return;
}
qmarksAfter = eciEncode("Windows_1256");
if (qmarksAfter == qmarksBefore) {
eciMode = 24;
encodeInfo += "Encoding in Windows-1256 character set\n";
return;
}
qmarksAfter = eciEncode("SJIS");
if (qmarksAfter == qmarksBefore) {
eciMode = 20;
encodeInfo += "Encoding in Shift-JIS character set\n";
return;
}
/* default */
qmarksAfter = eciEncode("UTF8");
eciMode = 26;
encodeInfo += "Encoding in UTF-8 character set\n";
}
protected int eciEncode(String charset) {
/* getBytes replaces unconverted characters to '?', so count
the number of question marks to find if conversion was sucessful.
*/
int i, qmarksAfter;
try {
inputBytes = content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
return -1;
}
qmarksAfter = 0;
for (i = 0; i < inputBytes.length; i++) {
if (inputBytes[i] == '?') {
qmarksAfter++;
}
}
return qmarksAfter;
}
abstract boolean encode();
protected void plotSymbol() {
int xBlock, yBlock;
double x, y, w, h;
boolean black;
rectangles.clear();
texts.clear();
int baseY;
if (humanReadableLocation == TOP) {
baseY = getTheoreticalHumanReadableHeight();
} else {
baseY = 0;
}
h = 0;
y = baseY;
for (yBlock = 0; yBlock < row_count; yBlock++) {
black = true;
x = 0;
for (xBlock = 0; xBlock < pattern[yBlock].length(); xBlock++) {
char c = pattern[yBlock].charAt(xBlock);
w = getModuleWidth(c - '0') * moduleWidth;
if (black) {
if (row_height[yBlock] == -1) {
h = default_height;
} else {
h = row_height[yBlock];
}
if (w != 0 && h != 0) {
Rectangle2D.Double rect = new Rectangle2D.Double(x, y, w, h);
rectangles.add(rect);
}
if (x + w > symbol_width) {
symbol_width = (int) Math.ceil(x + w);
}
}
black = !black;
x += w;
}
if ((y - baseY + h) > symbol_height) {
symbol_height = (int) Math.ceil(y - baseY + h);
}
y += h;
}
mergeVerticalBlocks();
if (humanReadableLocation != NONE && !readable.isEmpty()) {
double baseline;
if (humanReadableLocation == TOP) {
baseline = fontSize;
} else {
baseline = getHeight() + fontSize;
}
double centerX = getWidth() / 2;
texts.add(new TextBox(centerX, baseline, readable));
}
}
/**
* Returns the module width to use for the specified original module width, taking into account any module width ratio
* customizations. Intended to be overridden by subclasses that support such module width ratio customization.
*
* @param originalWidth the original module width
* @return the module width to use for the specified original module width
*/
protected double getModuleWidth(int originalWidth) {
return originalWidth;
}
/**
* Search for rectangles which have the same width and x position, and
* which join together vertically and merge them together to reduce the
* number of rectangles needed to describe a symbol.
*/
protected void mergeVerticalBlocks() {
for(int i = 0; i < rectangles.size() - 1; i++) {
for(int j = i + 1; j < rectangles.size(); j++) {
Rectangle2D.Double firstRect = rectangles.get(i);
Rectangle2D.Double secondRect = rectangles.get(j);
if (roughlyEqual(firstRect.x, secondRect.x) && roughlyEqual(firstRect.width, secondRect.width)) {
if (roughlyEqual(firstRect.y + firstRect.height, secondRect.y)) {
firstRect.height += secondRect.height;
rectangles.set(i, firstRect);
rectangles.remove(j);
}
}
}
}
}
protected String gs1SanityCheck(String source) {
// Enforce compliance with GS1 General Specification
// http://www.gs1.org/docs/gsmp/barcodes/GS1_General_Specifications.pdf
String reduced = "";
int i, j, last_ai;
boolean ai_latch;
String ai_string;
int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length;
int[] ai_value = new int[100];
int[] ai_location = new int[100];
int ai_count;
int[] data_location = new int[100];
int[] data_length = new int[100];
int src_len = source.length();
int error_latch;
/* Detect extended ASCII characters */
for (i = 0; i < src_len; i++) {
if (source.charAt(i) >= 128) {
error_msg += "Extended ASCII characters are not supported by GS1";
return "";
}
if (source.charAt(i) < 32) {
error_msg += "Control characters are not supported by GS1";
return "";
}
}
if (source.charAt(0) != '[') {
error_msg += "Data does not start with an AI";
return "";
}
/* Check the position of the brackets */
bracket_level = 0;
max_bracket_level = 0;
ai_length = 0;
max_ai_length = 0;
min_ai_length = 5;
j = 0;
ai_latch = false;
for (i = 0; i < src_len; i++) {
ai_length += j;
if (((j == 1) && (source.charAt(i) != ']'))
&& ((source.charAt(i) < '0') || (source.charAt(i) > '9'))) {
ai_latch = true;
}
if (source.charAt(i) == '[') {
bracket_level++;
j = 1;
}
if (source.charAt(i) == ']') {
bracket_level--;
if (ai_length < min_ai_length) {
min_ai_length = ai_length;
}
j = 0;
ai_length = 0;
}
if (bracket_level > max_bracket_level) {
max_bracket_level = bracket_level;
}
if (ai_length > max_ai_length) {
max_ai_length = ai_length;
}
}
min_ai_length--;
if (bracket_level != 0) {
/* Not all brackets are closed */
error_msg += "Malformed AI in input data (brackets don't match)";
return "";
}
if (max_bracket_level > 1) {
/* Nested brackets */
error_msg += "Found nested brackets in input data";
return "";
}
if (max_ai_length > 4) {
/* AI is too long */
error_msg += "Invalid AI in input data (AI too long)";
return "";
}
if (min_ai_length <= 1) {
/* AI is too short */
error_msg += "Invalid AI in input data (AI too short)";
return "";
}
if (ai_latch) {
/* Non-numeric data in AI */
error_msg += "Invalid AI in input data (non-numeric characters in AI)";
return "";
}
ai_count = 0;
for (i = 1; i < src_len; i++) {
if (source.charAt(i - 1) == '[') {
ai_location[ai_count] = i;
ai_value[ai_count] = 0;
for (j = 0; source.charAt(i + j) != ']'; j++) {
ai_value[ai_count] *= 10;
ai_value[ai_count] += Character.getNumericValue(source.charAt(i + j));
}
ai_count++;
}
}
for (i = 0; i < ai_count; i++) {
data_location[i] = ai_location[i] + 3;
if (ai_value[i] >= 100) {
data_location[i]++;
}
if (ai_value[i] >= 1000) {
data_location[i]++;
}
data_length[i] = source.length() - data_location[i];
for(j = source.length() - 1; j >= data_location[i]; j--) {
if (source.charAt(j) == '[') {
data_length[i] = j - data_location[i];
}
}
}
for (i = 0; i < ai_count; i++) {
if (data_length[i] == 0) {
/* No data for given AI */
error_msg += "Empty data field in input data";
return "";
}
}
error_latch = 0;
ai_string = "";
for (i = 0; i < ai_count; i++) {
switch (ai_value[i]) {
case 0:
if (data_length[i] != 18) {
error_latch = 1;
}
break;
case 1:
case 2:
case 3:
if (data_length[i] != 14) {
error_latch = 1;
}
break;
case 4:
if (data_length[i] != 16) {
error_latch = 1;
}
break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
if (data_length[i] != 6) {
error_latch = 1;
}
break;
case 20:
if (data_length[i] != 2) {
error_latch = 1;
}
break;
case 23:
case 24:
case 25:
case 39:
case 40:
case 41:
case 42:
case 70:
case 80:
case 81:
error_latch = 2;
break;
}
if (
((ai_value[i] >= 100) && (ai_value[i] <= 179))
|| ((ai_value[i] >= 1000) && (ai_value[i] <= 1799))
|| ((ai_value[i] >= 200) && (ai_value[i] <= 229))
|| ((ai_value[i] >= 2000) && (ai_value[i] <= 2299))
|| ((ai_value[i] >= 300) && (ai_value[i] <= 309))
|| ((ai_value[i] >= 3000) && (ai_value[i] <= 3099))
|| ((ai_value[i] >= 31) && (ai_value[i] <= 36))
|| ((ai_value[i] >= 310) && (ai_value[i] <= 369))) {
error_latch = 2;
}
if ((ai_value[i] >= 3100) && (ai_value[i] <= 3699)) {
if (data_length[i] != 6) {
error_latch = 1;
}
}
if (
((ai_value[i] >= 370) && (ai_value[i] <= 379))
|| ((ai_value[i] >= 3700) && (ai_value[i] <= 3799))) {
error_latch = 2;
}
if ((ai_value[i] >= 410) && (ai_value[i] <= 415)) {
if (data_length[i] != 13) {
error_latch = 1;
}
}
if (
((ai_value[i] >= 4100) && (ai_value[i] <= 4199))
|| ((ai_value[i] >= 700) && (ai_value[i] <= 703))
|| ((ai_value[i] >= 800) && (ai_value[i] <= 810))
|| ((ai_value[i] >= 900) && (ai_value[i] <= 999))
|| ((ai_value[i] >= 9000) && (ai_value[i] <= 9999))) {
error_latch = 2;
}
if (error_latch == 1) {
error_msg = "Invalid data length for AI";
return "";
}
if (error_latch == 2) {
error_msg = "Invalid AI value";
return "";
}
}
/* Resolve AI data - put resulting string in 'reduced' */
j = 0;
last_ai = 0;
ai_latch = false;
for (i = 0; i < src_len; i++) {
if ((source.charAt(i) != '[') && (source.charAt(i) != ']')) {
reduced += source.charAt(i);
}
if (source.charAt(i) == '[') {
/* Start of an AI string */
if (ai_latch) {
reduced += '[';
}
last_ai = (10 * Character.getNumericValue(source.charAt(i + 1)))
+ Character.getNumericValue(source.charAt(i + 2));
if ( ((last_ai >= 0) && (last_ai <= 4))
|| ((last_ai >= 11) && (last_ai <= 20))
|| (last_ai == 23) /* legacy support - see 5.3.8.2.2 */
|| ((last_ai >= 31) && (last_ai <= 36))
|| (last_ai == 41)) {
// The end of the current data block doesn't need FNC1
ai_latch = false;
} else {
// The end of the current data block does need FNC1
ai_latch = true;
}
}
/* The ']' character is simply dropped from the input */
}
/* the character '[' in the reduced string refers to the FNC1 character */
return reduced;
}
protected String hibcProcess(String source) {
char[] hibcCharTable = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$',
'/', '+', '%' };
int counter, i;
String to_process;
char check_digit;
if(source.length() > 36) {
error_msg = "Data too long for HIBC LIC";
return "";
}
source = source.toUpperCase();
if (!(source.matches("[A-Z0-9-\\. \\$/+\\%]+?"))) {
error_msg = "Invalid characters in input";
return "";
}
counter = 41;
for(i = 0; i < source.length(); i++) {
counter += positionOf(source.charAt(i), hibcCharTable);
}
counter = counter % 43;
if(counter < 10) {
check_digit = (char) (counter + '0');
} else {
if(counter < 36) {
check_digit = (char) ((counter - 10) + 'A');
} else {
switch(counter) {
case 36: check_digit = '-'; break;
case 37: check_digit = '.'; break;
case 38: check_digit = ' '; break;
case 39: check_digit = '$'; break;
case 40: check_digit = '/'; break;
case 41: check_digit = '+'; break;
case 42: check_digit = '%'; break;
default: check_digit = ' '; break; /* Keep compiler happy */
}
}
}
encodeInfo += "HIBC Check Digit: " + counter + " (" + check_digit + ")\n";
to_process = "+" + source + check_digit;
return to_process;
}
/**
* Returns the intermediate coding of this bar code. Symbol types that use the test
* infrastructure should override this method.
*
* @return the intermediate coding of this bar code
*/
protected int[] getCodewords() {
throw new UnsupportedOperationException();
}
/**
* Returns this bar code's pattern, converted into a set of corresponding codewords.
* Useful for bar codes that encode their content as a pattern.
*
* @param size the number of digits in each codeword
* @return this bar code's pattern, converted into a set of corresponding codewords
*/
protected int[] getPatternAsCodewords(int size) {
if (pattern == null || pattern.length == 0) {
return new int[0];
} else {
int count = (int) Math.ceil(pattern[0].length() / (double) size);
int[] codewords = new int[pattern.length * count];
for (int i = 0; i < pattern.length; i++) {
String row = pattern[i];
for (int j = 0; j < count; j++) {
int substringStart = j * size;
int substringEnd = Math.min((j + 1) * size, row.length());
codewords[(i * count) + j] = Integer.parseInt(row.substring(substringStart, substringEnd));
}
}
return codewords;
}
}
/**
* Inserts the specified array into the specified original array at the specified index.
*
* @param original the original array into which we want to insert another array
* @param index the index at which we want to insert the array
* @param inserted the array that we want to insert
* @return the combined array
*/
protected static int[] insert(int[] original, int index, int[] inserted) {
int[] modified = new int[original.length + inserted.length];
System.arraycopy(original, 0, modified, 0, index);
System.arraycopy(inserted, 0, modified, index, inserted.length);
System.arraycopy(original, index, modified, index + inserted.length, modified.length - index - inserted.length);
return modified;
}
/**
* Returns true if the specified array contains the specified value.
*
* @param values the array to check in
* @param value the value to check for
* @return true if the specified array contains the specified value
*/
protected static boolean contains(int[] values, int value) {
for (int i = 0; i < values.length; i++) {
if (values[i] == value) {
return true;
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy