package
net
.
sourceforge
.
barbecue
.
linear
.
code128
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
List
;
import
net
.
sourceforge
.
barbecue
.
BarcodeException
;
import
net
.
sourceforge
.
barbecue
.
BlankModule
;
import
net
.
sourceforge
.
barbecue
.
CompositeModule
;
import
net
.
sourceforge
.
barbecue
.
Module
;
import
net
.
sourceforge
.
barbecue
.
linear
.
LinearBarcode
;
* This is a concrete implementation of the Code 128 barcode. It fully supports all three
* available character sets (A, B and C), and also fully supports code shifts and set
* changes on-the-fly, providing an automatic optimisation mode.
public
class
Code128Barcode
extends
LinearBarcode
{
/** Character set A flag */
public
static
final
int
A
=
0
;
/** Character set B flag */
public
static
final
int
B
=
1
;
/** Character set c flag */
public
static
final
int
C
=
2
;
/** Auto character set flag */
public
static
final
int
O
=
3
;
/** Code shift character */
public
static
final
String
SHIFT
=
"
\306
"
;
/** Code set change from current to A character */
public
static
final
String
CHANGE_TO_A
=
"
\311
"
;
/** Code set change from current to B character */
public
static
final
String
CHANGE_TO_B
=
"
\310
"
;
/** Code set change from current to c character */
public
static
final
String
CHANGE_TO_C
=
"
\307
"
;
/** FNC1 start character */
public
static
final
String
FNC_1
=
"
\312
"
;
public
static
final
Module
START_A
=
new
Module
(
new
int
[] {
2
,
1
,
1
,
4
,
1
,
2
});
public
static
final
Module
START_B
=
new
Module
(
new
int
[] {
2
,
1
,
1
,
2
,
1
,
4
});
public
static
final
Module
START_C
=
new
Module
(
new
int
[] {
2
,
1
,
1
,
2
,
3
,
2
});
protected
static
final
Module
STOP
=
new
Module
(
new
int
[] {
2
,
3
,
3
,
1
,
1
,
1
,
2
});
protected
static
final
Module
QUIET_SECTION
=
new
BlankModule
(
10
);
private
static
final
Module
[]
START
= {
protected
static
final
int
[]
START_INDICES
= {
protected
static
final
int
[]
BUF_SIZES
= {
protected
int
startIndex
;
private
int
startingMode
;
private
boolean
shiftNext
;
private
boolean
shifted
;
private
Module
checkDigit
;
private
boolean
optimising
;
private
Accumulator
sum
;
private
Accumulator
index
;
* Create a new Code 128 barcode using character set B.
* @param data The data to encode
* @throws BarcodeException If the data to be encoded is invalid
public
Code128Barcode
(
String
data
)
throws
BarcodeException
{
* Creates a new Coded 128 barcode with the specified data and the specified
* @param data The data to encode
* @param mode The character set to use for encoding
* @throws BarcodeException If the data to be encoded is invalid
public
Code128Barcode
(
String
data
,
int
mode
)
throws
BarcodeException
{
this
.
startingMode
=
this
.
mode
;
this
.
shiftNext
=
false
;
this
.
startIndex
=
START_INDICES
[
this
.
mode
];
* Returns the current character set being used in this barcode.
* @return The flag indicating the current character set
public
int
getCharacterSet
() {
protected
String
beautify
(
String
s
) {
* Returns the width of the encoded symbol portion of the barcode in pixels for
* @param resolution The resolution to calculate the width for
* @return The width of the encoded portion of the barcode
protected
double
getSymbolWidth
(
int
resolution
) {
// L = (11C + 35)X (alphanumeric) L = (5.5C + 35)X (numeric only using Code C)
// L = length of symbol (not counting quiet zone)
// C = number of data characters, code characters and shift characters
// (do not include start, stop or checksum. They are automatically added in.)
double
barWidthMM
=
convertToMillimetres
(
getBarWidth
(),
resolution
);
if
(
startingMode
==
C
) {
return
(
multiplier
*
getData
().
length
() +
35
) *
barWidthMM
;
* Calculates the minimum allowed barcode height for the barcode. The height must
* be at least .15 times the length of the symbol (excluding quiet zones) and .25
* inches (whichever is larger).
* @param resolution The output resolution (for calculating the width)
* @return The minimum height
protected
int
calculateMinimumBarHeight
(
int
resolution
) {
// The height of the bars must be at least .15 times the symbol's length or .25 inches,
double
point25Inches
=
resolution
*
0.25
;
// TODO: Need to get rid of this and do it in the output class
return
(
int
)
Math
.
max
((
0.15
*
getSymbolWidth
(
resolution
)),
point25Inches
);
* Encodes the data of the barcode into bars.
* @return The encoded bar data
public
Module
[]
encodeData
() {
// We are calculating the check digit as we encode - this will ensure that it is
// calculated correctly, even with code changes to char set C
sum
=
new
Accumulator
(
startIndex
);
List
<
Module
>
modules
=
new
ArrayList
<
Module
>();
buf
=
new
CharBuffer
(
BUF_SIZES
[
mode
]);
index
=
new
Accumulator
(
1
);
String
data
=
getData
();
for
(
int
i
=
0
;
i
<
data
.
length
();
i
++) {
char
c
=
data
.
charAt
(
i
);
if
(
optimising
&&
startingMode
==
B
) {
if
(
i
+
1
<
data
.
length
() &&
isControl
(
c
) &&
mode
!=
A
) {
encode
(
modules
,
SHIFT
);
encode
(
modules
,
CHANGE_TO_A
);
}
else
if
(
i
+
3
<
data
.
length
() &&
digitGroupIsNext
(
i
,
data
) &&
mode
!=
C
) {
encode
(
modules
,
CHANGE_TO_C
);
}
else
if
(
i
+
1
<=
data
.
length
() &&
digitGroupEndIsNext
(
i
,
data
)
&&
mode
==
C
&&
buf
.
size
() !=
1
) {
encode
(
modules
,
CHANGE_TO_B
);
if
(
isShiftOrCode
(
c
)) {
encode
(
modules
,
String
.
valueOf
(
c
));
encode
(
modules
,
buf
.
toString
());
checkDigit
=
ModuleFactory
.
getModuleForIndex
(
sum
.
getValue
() %
103
,
mode
);
return
modules
.
toArray
(
new
Module
[
0
]);
private
boolean
isShiftOrCode
(
char
c
) {
String
s
=
String
.
valueOf
(
c
);
return
(
s
.
equals
(
SHIFT
)
||
s
.
equals
(
CHANGE_TO_A
)
||
s
.
equals
(
CHANGE_TO_B
)
||
s
.
equals
(
CHANGE_TO_C
)
||
s
.
equals
(
FNC_1
));
* Calculates the check sum digit for the barcode.
* @return The check sum digit
public
Module
calculateChecksum
() {
if
(
checkDigit
==
null
) {
* Returns the pre-amble for the barcode. This is a combination of a
* quiet section and the start character for the character set that the barcode
protected
Module
getPreAmble
() {
CompositeModule
module
=
new
CompositeModule
();
if
(
isDrawingQuietSection
()) {
module
.
add
(
QUIET_SECTION
);
module
.
add
(
START
[
mode
]);
* Returns the post amble for the barcode. This is the combination
* of the stop character anda quiet section.
protected
Module
getPostAmble
() {
CompositeModule
module
=
new
CompositeModule
();
if
(
isDrawingQuietSection
()) {
module
.
add
(
QUIET_SECTION
);
private
boolean
isControl
(
char
c
) {
return
Character
.
isISOControl
(
c
);
private
boolean
digitGroupIsNext
(
int
index
,
String
chars
) {
char
c1
=
chars
.
charAt
(
index
);
char
c2
=
chars
.
charAt
(
index
+
1
);
char
c3
=
chars
.
charAt
(
index
+
2
);
char
c4
=
chars
.
charAt
(
index
+
3
);
return
(
Character
.
isDigit
(
c1
)
&&
Character
.
isDigit
(
c2
)
&&
Character
.
isDigit
(
c3
)
&&
Character
.
isDigit
(
c4
));
private
boolean
digitGroupEndIsNext
(
int
index
,
String
chars
) {
if
(
index
==
chars
.
length
() -
1
) {
char
c1
=
chars
.
charAt
(
index
);
char
c2
=
chars
.
charAt
(
index
+
1
);
return
((
Character
.
isDigit
(
c1
) && (!
Character
.
isDigit
(
c2
)))
|| (!
Character
.
isDigit
(
c1
)));
* Pads the data to be encoded to an even length by prepending "0" characters.
* This is only valid for pure character set C barcodes.
private
void
padDataToEvenLength
() {
String
data
=
getData
();
if
(
startingMode
==
C
&&
data
.
length
() %
2
!=
0
&& !
containsShiftOrChange
(
data
)) {
private
boolean
containsShiftOrChange
(
String
data
) {
return
((
data
.
indexOf
(
CHANGE_TO_A
) >=
0
)
|| (
data
.
indexOf
(
CHANGE_TO_B
) >=
0
)
|| (
data
.
indexOf
(
CHANGE_TO_C
) >=
0
)
|| (
data
.
indexOf
(
SHIFT
) >=
0
));
private
void
clearShift
() {
private
void
checkShift
(
Module
module
) {
if
(
module
instanceof
ShiftModule
) {
}
else
if
(
shiftNext
) {
private
int
shiftMode
() {
private
void
checkCodeChange
(
Module
module
) {
if
(
module
instanceof
CodeChangeModule
) {
mode
= ((
CodeChangeModule
)
module
).
getCode
();
buf
=
new
CharBuffer
(
BUF_SIZES
[
mode
]);
private
void
encode
(
List
<
Module
>
modules
,
String
data
) {
Module
module
=
ModuleFactory
.
getModule
(
data
,
mode
);
checkCodeChange
(
module
);
modules
.
add
(
module
);
private
void
updateCheckSum
(
String
data
) {
int
code
=
ModuleFactory
.
getIndex
(
data
,
mode
);
sum
.
add
(
code
*
index
.
getValue
());
private
double
convertToMillimetres
(
double
barWidth
,
int
resolution
) {
double
pixelsPerMM
=
resolution
/
25.4
;
return
barWidth
/
pixelsPerMM
;