diff --git a/Source/interop/Encoding/DatamatrixEncodingOptions.cs b/Source/interop/Encoding/DatamatrixEncodingOptions.cs
index a6c4b911..ceeda2b4 100644
--- a/Source/interop/Encoding/DatamatrixEncodingOptions.cs
+++ b/Source/interop/Encoding/DatamatrixEncodingOptions.cs
@@ -124,6 +124,16 @@ public bool ForceC40
set { wrappedDatamatrixEncodingOptions.ForceC40 = value; }
}
+ ///
+ /// Specifies whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
+ /// DMRE symbols are never selected unless this option is explicitly enabled.
+ ///
+ public bool EnableDMRE
+ {
+ get { return wrappedDatamatrixEncodingOptions.EnableDMRE; }
+ set { wrappedDatamatrixEncodingOptions.EnableDMRE = value; }
+ }
+
///
/// Specifies what character encoding to use where applicable (type {@link String})
///
diff --git a/Source/lib/EncodeHintType.cs b/Source/lib/EncodeHintType.cs
index 92184cd7..5f38b6a7 100644
--- a/Source/lib/EncodeHintType.cs
+++ b/Source/lib/EncodeHintType.cs
@@ -214,6 +214,13 @@ public enum EncodeHintType
///
DATA_MATRIX_COMPACT,
+ ///
+ /// Whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
+ /// type: , or "true" or "false"
+ /// DMRE symbols are never selected unless this hint is explicitly enabled.
+ ///
+ DATA_MATRIX_DMRE,
+
///
/// 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
diff --git a/Source/lib/datamatrix/DataMatrixWriter.cs b/Source/lib/datamatrix/DataMatrixWriter.cs
index afffff21..71516bb1 100644
--- a/Source/lib/datamatrix/DataMatrixWriter.cs
+++ b/Source/lib/datamatrix/DataMatrixWriter.cs
@@ -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))
@@ -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
@@ -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);
diff --git a/Source/lib/datamatrix/encoder/DatamatrixEncodingOptions.cs b/Source/lib/datamatrix/encoder/DatamatrixEncodingOptions.cs
index 52188bc9..f4461a75 100644
--- a/Source/lib/datamatrix/encoder/DatamatrixEncodingOptions.cs
+++ b/Source/lib/datamatrix/encoder/DatamatrixEncodingOptions.cs
@@ -204,6 +204,39 @@ public bool CompactEncoding
}
}
+ ///
+ /// Specifies whether to enable Data Matrix Rectangular Extension (DMRE) symbol selection.
+ /// DMRE symbols are never selected unless this option is explicitly enabled.
+ ///
+#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);
+ }
+ }
+ }
+
///
/// 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.
diff --git a/Source/lib/datamatrix/encoder/EncoderContext.cs b/Source/lib/datamatrix/encoder/EncoderContext.cs
index b24529ad..de1a6a74 100644
--- a/Source/lib/datamatrix/encoder/EncoderContext.cs
+++ b/Source/lib/datamatrix/encoder/EncoderContext.cs
@@ -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;
@@ -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;
@@ -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);
}
}
diff --git a/Source/lib/datamatrix/encoder/HighLevelEncoder.cs b/Source/lib/datamatrix/encoder/HighLevelEncoder.cs
index 62723ee5..56ad5bc1 100644
--- a/Source/lib/datamatrix/encoder/HighLevelEncoder.cs
+++ b/Source/lib/datamatrix/encoder/HighLevelEncoder.cs
@@ -115,7 +115,7 @@ private static char randomize253State(int codewordPosition)
/// the encoded message (the char values range from 0 to 255)
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);
}
///
@@ -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);
}
///
@@ -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);
+ }
+
+ ///
+ /// Performs message encoding of a DataMatrix message using the algorithm described in annex P
+ /// of ISO/IEC 16022:2000(E).
+ ///
+ /// the message
+ /// requested shape. May be {@code SymbolShapeHint.FORCE_NONE},{@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.
+ /// the minimum symbol size constraint or null for no constraint
+ /// the maximum symbol size constraint or null for no constraint
+ /// encoding mode to start with
+ /// enforce C40 encoding
+ /// if true, DMRE symbols may be selected
+ /// the encoded message (the char values range from 0 to 255)
+ 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();
@@ -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))
{
diff --git a/Source/lib/datamatrix/encoder/SymbolInfo.cs b/Source/lib/datamatrix/encoder/SymbolInfo.cs
index bbddb519..98c1e6ab 100644
--- a/Source/lib/datamatrix/encoder/SymbolInfo.cs
+++ b/Source/lib/datamatrix/encoder/SymbolInfo.cs
@@ -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);
}
///
///
@@ -193,10 +193,30 @@ public static SymbolInfo lookup(int dataCodewords,
Dimension minSize,
Dimension maxSize,
bool fail)
+ {
+ return lookup(dataCodewords, shape, minSize, maxSize, fail, false);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// if true, DMRE symbols may be selected
+ ///
+ 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;
diff --git a/Source/test/src/datamatrix/DataMatrixWriterTestCase.cs b/Source/test/src/datamatrix/DataMatrixWriterTestCase.cs
index 54bf8018..8d11f9d7 100644
--- a/Source/test/src/datamatrix/DataMatrixWriterTestCase.cs
+++ b/Source/test/src/datamatrix/DataMatrixWriterTestCase.cs
@@ -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
@@ -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(() =>
+ 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));
+ }
}
}
\ No newline at end of file