Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve support for Macro PDF417 #973

Merged
merged 6 commits into from Mar 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
@@ -0,0 +1,9 @@
root = true

[*]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sure, what reads this? Eclipse et al? that's fine, those settings look standard and like what the project uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eclipse needs a plugin, but some others support it by default: http://editorconfig.org/

indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
111 changes: 110 additions & 1 deletion core/src/main/java/com/google/zxing/pdf417/PDF417ResultMetadata.java
Expand Up @@ -23,9 +23,21 @@ public final class PDF417ResultMetadata {

private int segmentIndex;
private String fileId;
private int[] optionalData;
private boolean lastSegment;
private int segmentCount = -1;
private String sender;
private String addressee;
private String fileName;
private long fileSize = -1;
private long timestamp = -1;
private int checksum = -1;
private int[] optionalData;

/**
* The Segment ID represents the segment of the whole file distributed over different symbols.
*
* @return File segment index
*/
public int getSegmentIndex() {
return segmentIndex;
}
Expand All @@ -34,6 +46,11 @@ public void setSegmentIndex(int segmentIndex) {
this.segmentIndex = segmentIndex;
}

/**
* Is the same for each related PDF417 symbol
*
* @return File ID
*/
public String getFileId() {
return fileId;
}
Expand All @@ -42,14 +59,27 @@ public void setFileId(String fileId) {
this.fileId = fileId;
}

/**
* @return always null
* @deprecated use dedicated already parsed fields
*/
@Deprecated
public int[] getOptionalData() {
return optionalData;
}

/**
* @deprecated parse and use new fields
*/
@Deprecated
public void setOptionalData(int[] optionalData) {
this.optionalData = optionalData;
}


/**
* @return true if it is the last segment
*/
public boolean isLastSegment() {
return lastSegment;
}
Expand All @@ -58,4 +88,83 @@ public void setLastSegment(boolean lastSegment) {
this.lastSegment = lastSegment;
}

/**
* @return count of segments, -1 if not set
*/
public int getSegmentCount() {
return segmentCount;
}

public void setSegmentCount(int segmentCount) {
this.segmentCount = segmentCount;
}

public String getSender() {
return sender;
}

public void setSender(String sender) {
this.sender = sender;
}

public String getAddressee() {
return addressee;
}

public void setAddressee(String addressee) {
this.addressee = addressee;
}

/**
* Filename of the encoded file
*
* @return filename
*/
public String getFileName() {
return fileName;
}

public void setFileName(String fileName) {
this.fileName = fileName;
}

/**
* filesize in bytes of the encoded file
*
* @return filesize in bytes, -1 if not set
*/
public long getFileSize() {
return fileSize;
}

public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}

/**
* 16-bit CRC checksum using CCITT-16
*
* @return crc checksum, -1 if not set
*/
public int getChecksum() {
return checksum;
}

public void setChecksum(int checksum) {
this.checksum = checksum;
}

/**
* unix epock timestamp, elapsed seconds since 1970-01-01
*
* @return elapsed seconds, -1 if not set
*/
public long getTimestamp() {
return timestamp;
}

public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}

}
Expand Up @@ -57,6 +57,14 @@ private enum Mode {
private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;
private static final int MAX_NUMERIC_CODEWORDS = 15;

private static final int MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME = 0;
private static final int MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT = 1;
private static final int MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP = 2;
private static final int MACRO_PDF417_OPTIONAL_FIELD_SENDER = 3;
private static final int MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE = 4;
private static final int MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE = 5;
private static final int MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM = 6;

private static final int PL = 25;
private static final int LL = 27;
private static final int AS = 27;
Expand All @@ -76,6 +84,7 @@ private enum Mode {
* This is used in the numeric compaction decode algorithm.
*/
private static final BigInteger[] EXP900;

static {
EXP900 = new BigInteger[16];
EXP900[0] = BigInteger.ONE;
Expand Down Expand Up @@ -124,7 +133,7 @@ static DecoderResult decode(int[] codewords, String ecLevel) throws FormatExcept
break;
case ECI_USER_DEFINED:
// Can't do anything with user ECI; skip its 1 character
codeIndex ++;
codeIndex++;
break;
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata);
Expand Down Expand Up @@ -155,7 +164,7 @@ static DecoderResult decode(int[] codewords, String ecLevel) throws FormatExcept
return decoderResult;
}

private static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata)
static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata)
throws FormatException {
if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) {
// we must have at least two bytes left for the segment index
Expand All @@ -172,35 +181,72 @@ private static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417Result
codeIndex = textCompaction(codewords, codeIndex, fileId);
resultMetadata.setFileId(fileId.toString());

switch (codewords[codeIndex]) {
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
codeIndex++;
int[] additionalOptionCodeWords = new int[codewords[0] - codeIndex];
int additionalOptionCodeWordsIndex = 0;
int optionalFieldsStart = -1;
if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) {
optionalFieldsStart = codeIndex + 1;
}

boolean end = false;
while ((codeIndex < codewords[0]) && !end) {
int code = codewords[codeIndex++];
if (code < TEXT_COMPACTION_MODE_LATCH) {
additionalOptionCodeWords[additionalOptionCodeWordsIndex++] = code;
} else {
switch (code) {
case MACRO_PDF417_TERMINATOR:
resultMetadata.setLastSegment(true);
codeIndex++;
end = true;
break;
default:
throw FormatException.getFormatInstance();
}
while (codeIndex < codewords[0]) {
switch (codewords[codeIndex]) {
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
codeIndex++;
switch (codewords[codeIndex]) {
case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME:
StringBuilder fileName = new StringBuilder();
codeIndex = textCompaction(codewords, codeIndex + 1, fileName);
resultMetadata.setFileName(fileName.toString());
break;
case MACRO_PDF417_OPTIONAL_FIELD_SENDER:
StringBuilder sender = new StringBuilder();
codeIndex = textCompaction(codewords, codeIndex + 1, sender);
resultMetadata.setSender(sender.toString());
break;
case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE:
StringBuilder addressee = new StringBuilder();
codeIndex = textCompaction(codewords, codeIndex + 1, addressee);
resultMetadata.setAddressee(addressee.toString());
break;
case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT:
StringBuilder segmentCount = new StringBuilder();
codeIndex = numericCompaction(codewords, codeIndex + 1, segmentCount);
resultMetadata.setSegmentCount(Integer.parseInt(segmentCount.toString()));
break;
case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP:
StringBuilder timestamp = new StringBuilder();
codeIndex = numericCompaction(codewords, codeIndex + 1, timestamp);
resultMetadata.setTimestamp(Long.parseLong(timestamp.toString()));
break;
case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM:
StringBuilder checksum = new StringBuilder();
codeIndex = numericCompaction(codewords, codeIndex + 1, checksum);
resultMetadata.setChecksum(Integer.parseInt(checksum.toString()));
break;
case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE:
StringBuilder fileSize = new StringBuilder();
codeIndex = numericCompaction(codewords, codeIndex + 1, fileSize);
resultMetadata.setFileSize(Long.parseLong(fileSize.toString()));
break;
default:
throw FormatException.getFormatInstance();
}
}
resultMetadata.setOptionalData(Arrays.copyOf(additionalOptionCodeWords, additionalOptionCodeWordsIndex));
break;
case MACRO_PDF417_TERMINATOR:
resultMetadata.setLastSegment(true);
codeIndex++;
break;
break;
case MACRO_PDF417_TERMINATOR:
codeIndex++;
resultMetadata.setLastSegment(true);
break;
default:
throw FormatException.getFormatInstance();
}
}

// copy optional fields to additional options
if (optionalFieldsStart != -1) {
int optionalFieldsLength = codeIndex - optionalFieldsStart;
if (resultMetadata.isLastSegment()) {
// do not include terminator
optionalFieldsLength--;
}
resultMetadata.setOptionalData(Arrays.copyOfRange(codewords, optionalFieldsStart, optionalFieldsStart + optionalFieldsLength));
}

return codeIndex;
Expand Down
Expand Up @@ -24,8 +24,8 @@ public final class PDF417BlackBox3TestCase extends AbstractBlackBoxTestCase {

public PDF417BlackBox3TestCase() {
super("src/test/resources/blackbox/pdf417-3", new MultiFormatReader(), BarcodeFormat.PDF_417);
addTest(18, 18, 0, 0, 0.0f);
addTest(18, 18, 0, 0, 180.0f);
addTest(19, 19, 0, 0, 0.0f);
addTest(19, 19, 0, 0, 180.0f);
}

}
Expand Up @@ -64,7 +64,7 @@ public final class PDF417BlackBox4TestCase extends AbstractBlackBoxTestCase {

public PDF417BlackBox4TestCase() {
super("src/test/resources/blackbox/pdf417-4", null, BarcodeFormat.PDF_417);
testResults.add(new TestResult(2, 2, 0, 0, 0.0f));
testResults.add(new TestResult(3, 3, 0, 0, 0.0f));
}

@Test
Expand Down