Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Source/interop/Encoding/DatamatrixEncodingOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ public bool ForceC40
set { wrappedDatamatrixEncodingOptions.ForceC40 = value; }
}

/// <summary>
/// Specifies whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
/// DMRE symbols are never selected unless this option is explicitly enabled.
/// </summary>
public bool EnableDMRE
{
get { return wrappedDatamatrixEncodingOptions.EnableDMRE; }
set { wrappedDatamatrixEncodingOptions.EnableDMRE = value; }
}

/// <summary>
/// Specifies what character encoding to use where applicable (type {@link String})
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions Source/lib/EncodeHintType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ public enum EncodeHintType
/// </summary>
DATA_MATRIX_COMPACT,

/// <summary>
/// Whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
/// type: <see cref="System.Boolean" />, or "true" or "false"
/// DMRE symbols are never selected unless this hint is explicitly enabled.
/// </summary>
DATA_MATRIX_DMRE,

/// <summary>
/// Specifies whether to use compact mode for Code-128 code (type {@link Boolean}, or "true" or "false"
/// This can yield slightly smaller bar codes. This option and {@link #FORCE_CODE_SET} are mutually
Expand Down
6 changes: 4 additions & 2 deletions Source/lib/datamatrix/DataMatrixWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public BitMatrix encode(String contents, BarcodeFormat format, int width, int he
var noPadding = false;
System.Text.Encoding encoding = null;
var disableEci = false;
var allowDMRE = false;
if (hints != null)
{
if (hints.ContainsKey(EncodeHintType.DATA_MATRIX_SHAPE))
Expand Down Expand Up @@ -130,6 +131,7 @@ public BitMatrix encode(String contents, BarcodeFormat format, int width, int he
}
encoding = IDictionaryExtensions.GetEncoding(hints, null);
disableEci = IDictionaryExtensions.IsBooleanFlagSet(hints, EncodeHintType.DISABLE_ECI, disableEci);
allowDMRE = IDictionaryExtensions.IsBooleanFlagSet(hints, EncodeHintType.DATA_MATRIX_DMRE, allowDMRE);
}

//1. step: Data encodation
Expand All @@ -144,10 +146,10 @@ public BitMatrix encode(String contents, BarcodeFormat format, int width, int he
else
{
var hasForceC40Hint = IDictionaryExtensions.IsBooleanFlagSet(hints, EncodeHintType.FORCE_C40);
encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize, defaultEncodation, hasForceC40Hint, encoding, disableEci);
encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize, defaultEncodation, hasForceC40Hint, encoding, disableEci, allowDMRE);
}

SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.Length, shape, minSize, maxSize, true);
SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.Length, shape, minSize, maxSize, true, allowDMRE);

//2. step: ECC generation
String codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo);
Expand Down
33 changes: 33 additions & 0 deletions Source/lib/datamatrix/encoder/DatamatrixEncodingOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,39 @@ public bool CompactEncoding
}
}

/// <summary>
/// Specifies whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
/// DMRE symbols are never selected unless this option is explicitly enabled.
/// </summary>
#if !NETSTANDARD && !NETFX_CORE && !PORTABLE && !UNITY
[CategoryAttribute("Standard"), DescriptionAttribute("Specifies whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.")]
#endif
public bool EnableDMRE
{
get
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_DMRE))
{
var boolObj = Hints[EncodeHintType.DATA_MATRIX_DMRE];
if (boolObj != null)
return (bool)boolObj;
}
return false;
}
set
{
if (value)
{
Hints[EncodeHintType.DATA_MATRIX_DMRE] = value;
}
else
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_DMRE))
Hints.Remove(EncodeHintType.DATA_MATRIX_DMRE);
}
}
}

/// <summary>
/// Forces C40 encoding for data-matrix (type {@link Boolean}, or "true" or "false") {@link String } value). This
/// option and {@link #DATA_MATRIX_COMPACT} are mutually exclusive.
Expand Down
8 changes: 7 additions & 1 deletion Source/lib/datamatrix/encoder/EncoderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ internal sealed class EncoderContext
private SymbolShapeHint shape;
private Dimension minSize;
private Dimension maxSize;
private bool allowDMRE;
private readonly StringBuilder codewords;
private int pos;
private int newEncoding;
Expand Down Expand Up @@ -84,6 +85,11 @@ public void setSizeConstraints(Dimension minSize, Dimension maxSize)
this.maxSize = maxSize;
}

public void setAllowDMRE(bool allowDMRE)
{
this.allowDMRE = allowDMRE;
}

public void setSkipAtEnd(int count)
{
this.skipAtEnd = count;
Expand Down Expand Up @@ -148,7 +154,7 @@ public void updateSymbolInfo(int len)
{
if (this.symbolInfo == null || len > this.symbolInfo.dataCapacity)
{
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true);
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true, allowDMRE);
}
}

Expand Down
30 changes: 28 additions & 2 deletions Source/lib/datamatrix/encoder/HighLevelEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private static char randomize253State(int codewordPosition)
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
public static String encodeHighLevel(String msg)
{
return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null, Encodation.ASCII, false, null, false);
return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null, Encodation.ASCII, false, null, false, false);
}

/// <summary>
Expand All @@ -134,7 +134,7 @@ public static String encodeHighLevel(String msg,
Dimension maxSize,
int defaultEncodation)
{
return encodeHighLevel(msg, shape, minSize, maxSize, defaultEncodation, false, null, false);
return encodeHighLevel(msg, shape, minSize, maxSize, defaultEncodation, false, null, false, false);
}

/// <summary>
Expand All @@ -156,6 +156,31 @@ public static String encodeHighLevel(String msg,
bool forceC40,
Encoding encoding,
bool disableEci)
{
return encodeHighLevel(msg, shape, minSize, maxSize, defaultEncodation, forceC40, encoding, disableEci, false);
}

/// <summary>
/// Performs message encoding of a DataMatrix message using the algorithm described in annex P
/// of ISO/IEC 16022:2000(E).
/// </summary>
/// <param name="msg">the message</param>
/// <param name="shape">requested shape. May be {@code SymbolShapeHint.FORCE_NONE},{@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.</param>
/// <param name="minSize">the minimum symbol size constraint or null for no constraint</param>
/// <param name="maxSize">the maximum symbol size constraint or null for no constraint</param>
/// <param name="defaultEncodation">encoding mode to start with</param>
/// <param name="forceC40">enforce C40 encoding</param>
/// <param name="allowDMRE">if true, DMRE symbols may be selected</param>
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
public static String encodeHighLevel(String msg,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
int defaultEncodation,
bool forceC40,
Encoding encoding,
bool disableEci,
bool allowDMRE)
{
//the codewords 0..255 are encoded as Unicode characters
C40Encoder c40Encoder = new C40Encoder();
Expand All @@ -168,6 +193,7 @@ public static String encodeHighLevel(String msg,
var context = new EncoderContext(msg, encoding, disableEci);
context.setSymbolShape(shape);
context.setSizeConstraints(minSize, maxSize);
context.setAllowDMRE(allowDMRE);

if (msg.StartsWith(MACRO_05_HEADER) && msg.EndsWith(MACRO_TRAILER))
{
Expand Down
24 changes: 22 additions & 2 deletions Source/lib/datamatrix/encoder/SymbolInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public static SymbolInfo lookup(int dataCodewords, bool allowRectangular, bool f

private static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape, bool fail)
{
return lookup(dataCodewords, shape, null, null, fail);
return lookup(dataCodewords, shape, null, null, fail, false);
}
/// <summary>
///
Expand All @@ -193,10 +193,30 @@ public static SymbolInfo lookup(int dataCodewords,
Dimension minSize,
Dimension maxSize,
bool fail)
{
return lookup(dataCodewords, shape, minSize, maxSize, fail, false);
}

/// <summary>
///
/// </summary>
/// <param name="dataCodewords"></param>
/// <param name="shape"></param>
/// <param name="minSize"></param>
/// <param name="maxSize"></param>
/// <param name="fail"></param>
/// <param name="allowDMRE">if true, DMRE symbols may be selected</param>
/// <returns></returns>
public static SymbolInfo lookup(int dataCodewords,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
bool fail,
bool allowDMRE)
{
foreach (SymbolInfo symbol in symbols)
{
if (symbol.dmre)
if (symbol.dmre && !allowDMRE)
// DMRE Symbols doesn't work in all cases
continue;

Expand Down
113 changes: 112 additions & 1 deletion Source/test/src/datamatrix/DataMatrixWriterTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ public void test0To256AsOneStringRoundTrip(string encodingStr)
[TestCase('1')]
[TestCase('a')]
[TestCase('A')]
[TestCase('')]
[TestCase('')]
public void testCharactersForLengthUntil256RoundTrip(char character)
{
var writer = new BarcodeWriter
Expand Down Expand Up @@ -370,5 +370,116 @@ public void testCharactersForLengthUntil256RoundTrip(char character)
if (errors.Count > 0)
throw new AssertionException("not every content could be encoded and decoded");
}

[Test]
public void testDefaultDoesNotSelectDMRE()
{
// 33 digits encode to ~17 codewords (16 pairs + 1 single digit).
// Without DMRE and FORCE_RECTANGLE: skips rect cap=5, cap=10, cap=16 symbols,
// then skips DMRE 8x48 (dmre=true), lands on rect cap=22 (SymbolInfo 22x18@16x10r2 -> 36x12).
var content = "123456789012345678901234567890123"; // 33 digits -> 17 codewords
var options = new DatamatrixEncodingOptions
{
SymbolShape = SymbolShapeHint.FORCE_RECTANGLE,
};
var matrix = new DataMatrixWriter().encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints);
Assert.That(matrix, Is.Not.Null);
// Should be a standard rectangular symbol (36x12), NOT DMRE 48x8
Assert.That(matrix.Width, Is.EqualTo(36));
Assert.That(matrix.Height, Is.EqualTo(12));
}

[Test]
public void testDMREOptInSelectsDMRESymbol()
{
// Same payload, but with DMRE enabled and FORCE_RECTANGLE
// 33 digits -> 17 codewords, fits DMRE 8x48 (cap=18), skips rect cap=5/10/16
var content = "123456789012345678901234567890123"; // 33 digits -> 17 codewords
var options = new DatamatrixEncodingOptions
{
SymbolShape = SymbolShapeHint.FORCE_RECTANGLE,
EnableDMRE = true
};
var matrix = new DataMatrixWriter().encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints);
Assert.That(matrix, Is.Not.Null);
// Should select DMRE 8x48 (48x8) instead of standard 36x12
Assert.That(matrix.Width, Is.EqualTo(48));
Assert.That(matrix.Height, Is.EqualTo(8));
}

[Test]
public void testDMREExactSizeViaMinMax()
{
// Constrain to DMRE 8x48 dimensions with DMRE enabled
var content = "Hello";
var options = new DatamatrixEncodingOptions
{
MinSize = new Dimension(48, 8),
MaxSize = new Dimension(48, 8),
EnableDMRE = true
};
var matrix = new DataMatrixWriter().encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints);
Assert.That(matrix, Is.Not.Null);
Assert.That(matrix.Width, Is.EqualTo(48));
Assert.That(matrix.Height, Is.EqualTo(8));
}

[Test]
public void testDMREWithoutOptInFailsWithExactDMREConstraints()
{
// Same min/max constraint but without EnableDMRE - DMRE symbol is skipped
var content = "Hello";
var options = new DatamatrixEncodingOptions
{
MinSize = new Dimension(48, 8),
MaxSize = new Dimension(48, 8),
// EnableDMRE not set - defaults to false
};
// No standard symbol matches 48x8, so we expect an exception
Assert.Throws<ArgumentException>(() =>
new DataMatrixWriter().encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints));
}

[Test]
public void testDMRECapacityBoundaryFallsThroughToNextSymbol()
{
// 35 digits encode to 18 digit-pair codewords? Actually:
// 34 digits -> 17 codewords, 35 digits -> 18 codewords.
// To exceed 8x48 capacity 18, use 37 digits -> 19 codewords.
var content = "1234567890123456789012345678901234567"; // 37 digits -> 19 codewords

var options = new DatamatrixEncodingOptions
{
EnableDMRE = true,
SymbolShape = SymbolShapeHint.FORCE_RECTANGLE
};

var matrix = new DataMatrixWriter().encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints);

Assert.That(matrix, Is.Not.Null);
Assert.That(matrix.Width, Is.Not.EqualTo(48));
Assert.That(matrix.Height, Is.Not.EqualTo(8));
}

[Test]
public void testDMREOptInRoundTrip()
{
// Round-trip encode/decode with DMRE enabled using Internal.Decoder on the raw matrix
var content = "123456789012345678901234567890123"; // 33 digits -> 17 codewords
var options = new DatamatrixEncodingOptions
{
EnableDMRE = true,
SymbolShape = SymbolShapeHint.FORCE_RECTANGLE
};
var writer = new DataMatrixWriter();
var matrix = writer.encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, options.Hints);
Assert.That(matrix, Is.Not.Null);
Assert.That(matrix.Width, Is.EqualTo(48));
Assert.That(matrix.Height, Is.EqualTo(8));

var res = new Internal.Decoder().decode(matrix);
Assert.That(res, Is.Not.Null);
Assert.That(res.Text, Is.EqualTo(content));
}
}
}