This seemed like a fun challenge, so, done.
Piggybacked a function off zxing, which epicor has included in SaaS on server side assemblies…
Use the function in a pre bpm on .SubmitToAgent for your report of choice. Put the base64png output into CallContextBpmData in a string column. Add CallContextBpmData to your report as a new datasource (I have another post here with a how-to on this)
Edit: Corrected to CallContextBpmData and link to post: SSRS - Feeding report style number/description into RDL - #8 by GabeFranco
This will give you availability to the generated 2d barcode within your report. I’m doing absolutely no validation here so if you don’t get an output barcode take a look at the log output in msg. You’ve probably fed in some data that the selected barcode type does not support.
Possible values for Symbology:
QR
MICROQR
DATAMATRIX
CODE128
CODE39
AZTEC
PDF417
EAN13
EAN8
UPCA
CODABAR
ITF
Old & Nasty
//References: zxing.dll
//Signature:
//Input: symbology (string), data (string), scale (decimal)
//Output: msg (string), base64png (string)
//Usings:
//using System.IO;
//using System.IO.Compression;
//using ZXing;
//using ZXing.Common;
msg = "";
base64png = null;
var log = new Action<string>(txt => msg += $"[{txt}] § ");
log("Pipeline Initialized");
try
{
Func<uint, byte[]> GetBigEndianBytes = value => new byte[]
{
(byte)((value >> 24) & 255u),
(byte)((value >> 16) & 255u),
(byte)((value >> 8) & 255u),
(byte)(value & 255u)
};
log("GetBigEndianBytes Created");
Func<byte[], uint> ComputeCrc32 = bytes =>
{
uint crc = 4294967295u;
if (bytes == null || bytes.Length == 0)
{
return crc ^ 4294967295u;
}
for (int index = 0; index < bytes.Length; index++)
{
crc ^= bytes[index];
for (int bit = 0; bit < 8; bit++)
{
bool applyPolynomial = (crc & 1u) == 1u;
crc >>= 1;
if (applyPolynomial)
{
crc ^= 3988292384u;
}
}
}
return crc ^ 4294967295u;
};
log("ComputeCrc32 Created");
Func<byte[], uint> ComputeAdler32 = buffer =>
{
const uint modulus = 65521u;
uint sumA = 1u;
uint sumB = 0u;
if (buffer == null || buffer.Length == 0)
{
return 1u;
}
for (int index = 0; index < buffer.Length; index++)
{
sumA = (sumA + buffer[index]) % modulus;
sumB = (sumB + sumA) % modulus;
}
return (sumB << 16) | sumA;
};
log("ComputeAdler32 Created");
Action<MemoryStream, byte[], byte[]> WritePngChunk = (stream, chunkType, chunkData) =>
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (chunkType == null || chunkType.Length != 4)
{
throw new ArgumentException("PNG chunk types must be exactly four bytes long.", "chunkType");
}
byte[] safeChunkData = chunkData ?? new byte[0];
byte[] payloadLengthBytes = GetBigEndianBytes((uint)safeChunkData.Length);
stream.Write(payloadLengthBytes, 0, payloadLengthBytes.Length);
stream.Write(chunkType, 0, chunkType.Length);
if (safeChunkData.Length > 0)
{
stream.Write(safeChunkData, 0, safeChunkData.Length);
}
byte[] crcInput = new byte[chunkType.Length + safeChunkData.Length];
Buffer.BlockCopy(chunkType, 0, crcInput, 0, chunkType.Length);
if (safeChunkData.Length > 0)
{
Buffer.BlockCopy(safeChunkData, 0, crcInput, chunkType.Length, safeChunkData.Length);
}
byte[] crcBytes = GetBigEndianBytes(ComputeCrc32(crcInput));
stream.Write(crcBytes, 0, crcBytes.Length);
};
log("WritePngChunk Created");
Func<byte[], byte[]> CompressToZlib = buffer =>
{
byte[] safeBuffer = buffer ?? new byte[0];
byte[] deflateBytes = null;
using (MemoryStream compressedStream = new MemoryStream())
{
using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
{
deflateStream.Write(safeBuffer, 0, safeBuffer.Length);
}
deflateBytes = compressedStream.ToArray();
}
byte[] zlibPayload = new byte[2 + deflateBytes.Length + 4];
zlibPayload[0] = 120;
zlibPayload[1] = 156;
if (deflateBytes.Length > 0)
{
Buffer.BlockCopy(deflateBytes, 0, zlibPayload, 2, deflateBytes.Length);
}
byte[] adlerBytes = GetBigEndianBytes(ComputeAdler32(safeBuffer));
Buffer.BlockCopy(adlerBytes, 0, zlibPayload, 2 + deflateBytes.Length, adlerBytes.Length);
return zlibPayload;
};
log("CompressToZlib Created");
Func<Dictionary<string, BarcodeFormat>> GetSymbologyFormats = () => new Dictionary<string, BarcodeFormat>
{
{ "QR", BarcodeFormat.QR_CODE },
{ "MICROQR", BarcodeFormat.QR_CODE },
{ "DATAMATRIX", BarcodeFormat.DATA_MATRIX },
{ "CODE128", BarcodeFormat.CODE_128 },
{ "CODE39", BarcodeFormat.CODE_39 },
{ "AZTEC", BarcodeFormat.AZTEC },
{ "PDF417", BarcodeFormat.PDF_417 },
{ "EAN13", BarcodeFormat.EAN_13 },
{ "EAN8", BarcodeFormat.EAN_8 },
{ "UPCA", BarcodeFormat.UPC_A },
{ "CODABAR", BarcodeFormat.CODABAR },
{ "ITF", BarcodeFormat.ITF }
};
log("GetSymbologyFormats Created");
log($"Original Inputs -> Symbology: {symbology}, DataLength: {(data != null ? data.Length.ToString() : "null")}, Scale: {scale}");
symbology = string.IsNullOrEmpty(symbology) ? "QR" : symbology;
data = string.IsNullOrEmpty(data) ? "https://example.com" : data;
scale = scale <= 0m ? 1.0m : scale;
log($"Defaulted Inputs -> Symbology: {symbology}, DataLength: {data.Length}, Scale: {scale}");
log("Validating Inputs");
if (string.IsNullOrWhiteSpace(data))
{
throw new ArgumentException("The data string to encode cannot be null, empty, or whitespace.", "data");
}
if (string.IsNullOrWhiteSpace(symbology))
{
throw new ArgumentException("The symbology definition must be provided.", "symbology");
}
log("Inputs Validated Successfully");
log("Resolving Symbology");
string normalizedSymbology = symbology.Trim().ToUpperInvariant();
var symbologyFormats = GetSymbologyFormats();
BarcodeFormat format;
if (!symbologyFormats.TryGetValue(normalizedSymbology, out format))
{
throw new ArgumentException(
"Unsupported symbology: '" + symbology + "'. Supported values: " +
string.Join(", ", symbologyFormats.Keys) + ".",
"symbology"
);
}
log($"Resolved Symbology: {normalizedSymbology} to Format: {format}");
log("Configuring EncodingOptions");
var encodingOptions = new EncodingOptions
{
Width = 1,
Height = 1,
Margin = 0,
PureBarcode = true
};
log($"EncodingOptions set - Width: {encodingOptions.Width}, Height: {encodingOptions.Height}, Margin: {encodingOptions.Margin}, PureBarcode: {encodingOptions.PureBarcode}");
if (normalizedSymbology == "MICROQR")
{
log("Applying MICROQR Version Hint");
encodingOptions.Hints[ZXing.EncodeHintType.QR_VERSION] = 1;
}
log("Initializing MultiFormatWriter");
var writer = new ZXing.MultiFormatWriter();
log("Calling MultiFormatWriter.encode...");
BitMatrix bitMatrix = writer.encode(data, format, encodingOptions.Width, encodingOptions.Height, encodingOptions.Hints);
if (bitMatrix == null)
{
throw new InvalidOperationException("ZXing MultiFormatWriter.encode returned null BitMatrix.");
}
log($"BitMatrix Generated - Width: {bitMatrix.Width}, Height: {bitMatrix.Height}");
log("Setting up Raster Buffer Rendering");
int scaleFactor = Math.Max(1, (int)Math.Ceiling(scale));
int scaledWidth = bitMatrix.Width * scaleFactor;
int scaledHeight = bitMatrix.Height * scaleFactor;
int bytesPerPixel = 4;
int rgbaStride = scaledWidth * bytesPerPixel;
log($"Calculated Raster Bounds -> Width: {scaledWidth}, Height: {scaledHeight}, ScaleFactor: {scaleFactor}");
byte[] rgba = new byte[scaledWidth * scaledHeight * bytesPerPixel];
log($"Allocated RGBA Buffer -> Length: {rgba.Length} bytes");
for (int pixelOffset = 0; pixelOffset < rgba.Length; pixelOffset += bytesPerPixel)
{
rgba[pixelOffset] = 255;
rgba[pixelOffset + 1] = 255;
rgba[pixelOffset + 2] = 255;
rgba[pixelOffset + 3] = 255;
}
log("RGBA Buffer Cleared to White");
int paintedModules = 0;
for (int matrixY = 0; matrixY < bitMatrix.Height; matrixY++)
{
for (int matrixX = 0; matrixX < bitMatrix.Width; matrixX++)
{
if (!bitMatrix[matrixX, matrixY])
{
continue;
}
paintedModules++;
for (int offsetY = 0; offsetY < scaleFactor; offsetY++)
{
int pixelY = (matrixY * scaleFactor) + offsetY;
int rowOffset = pixelY * rgbaStride;
for (int offsetX = 0; offsetX < scaleFactor; offsetX++)
{
int pixelX = (matrixX * scaleFactor) + offsetX;
int modulePixelOffset = rowOffset + (pixelX * bytesPerPixel);
rgba[modulePixelOffset] = 0;
rgba[modulePixelOffset + 1] = 0;
rgba[modulePixelOffset + 2] = 0;
rgba[modulePixelOffset + 3] = 255;
}
}
}
}
log($"Raster Buffer Rendered - Painted {paintedModules} black modules");
log("Packing PNG Scanlines");
int scanlineLength = 1 + rgbaStride;
byte[] scanlines = new byte[scaledHeight * scanlineLength];
for (int row = 0; row < scaledHeight; row++)
{
int scanlineOffset = row * scanlineLength;
scanlines[scanlineOffset] = 0;
Buffer.BlockCopy(rgba, row * rgbaStride, scanlines, scanlineOffset + 1, rgbaStride);
}
log($"PNG Scanlines Packed -> Total Length: {scanlines.Length} bytes");
log("Beginning PNG Export to Base64");
byte[] pngSignature = new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 };
byte[] ihdrType = new byte[] { 73, 72, 68, 82 };
byte[] idatType = new byte[] { 73, 68, 65, 84 };
byte[] iendType = new byte[] { 73, 69, 78, 68 };
byte[] ihdrData = new byte[13];
byte[] widthBytes = GetBigEndianBytes((uint)scaledWidth);
byte[] heightBytes = GetBigEndianBytes((uint)scaledHeight);
Buffer.BlockCopy(widthBytes, 0, ihdrData, 0, widthBytes.Length);
Buffer.BlockCopy(heightBytes, 0, ihdrData, 4, heightBytes.Length);
ihdrData[8] = 8;
ihdrData[9] = 6;
ihdrData[10] = 0;
ihdrData[11] = 0;
ihdrData[12] = 0;
log("Compressing Scanlines via Zlib");
byte[] compressedScanlines = CompressToZlib(scanlines);
log($"Scanlines Compressed -> Zlib Payload Length: {compressedScanlines.Length} bytes");
using (MemoryStream pngStream = new MemoryStream())
{
pngStream.Write(pngSignature, 0, pngSignature.Length);
WritePngChunk(pngStream, ihdrType, ihdrData);
log("IHDR Chunk Written");
WritePngChunk(pngStream, idatType, compressedScanlines);
log("IDAT Chunk Written");
WritePngChunk(pngStream, iendType, new byte[0]);
log("IEND Chunk Written");
base64png = Convert.ToBase64String(pngStream.ToArray());
}
log("PNG Encoded to Base64 String");
log($"DataLength: {data.Length}");
log($"Scale: {scale} (Factor: {scaleFactor})");
log($"MatrixSize: {bitMatrix.Width}x{bitMatrix.Height}");
log($"ImageSize: {scaledWidth}x{scaledHeight}");
log($"Base64Length: {base64png.Length}");
log("Pipeline Completed Successfully");
}
catch (Exception ex)
{
msg += $"\r\n[FATAL ERROR] {ex.Message} \r\nStackTrace: {ex.StackTrace} § ";
log("Pipeline Execution Failed");
if (ex.InnerException != null)
{
msg += $"\r\n[INNER EXCEPTION] {ex.InnerException.Message} \r\nStackTrace: {ex.InnerException.StackTrace} § ";
}
}
// References: zxing.dll
// Signature:
// Input: symbology (string), data (string), scale (decimal)
// Output: msg (string), base64png (string)
// Usings:
// using System;
// using System.Collections.Generic;
// using System.IO;
// using System.IO.Compression;
// using ZXing;
// using ZXing.Common;
msg = "";
base64png = null;
var log = new Action<string>(txt => msg += $"[{txt}] § ");
log("Pipeline Initialized");
try
{
Func<uint, byte[]> GetBigEndianBytes = value => new byte[]
{
(byte)((value >> 24) & 255u),
(byte)((value >> 16) & 255u),
(byte)((value >> 8) & 255u),
(byte)(value & 255u)
};
log("GetBigEndianBytes Created");
Func<byte[], uint> ComputeCrc32 = bytes =>
{
uint crc = 4294967295u;
if (bytes == null || bytes.Length == 0)
{
return crc ^ 4294967295u;
}
for (int index = 0; index < bytes.Length; index++)
{
crc ^= bytes[index];
for (int bit = 0; bit < 8; bit++)
{
bool applyPolynomial = (crc & 1u) == 1u;
crc >>= 1;
if (applyPolynomial)
{
crc ^= 3988292384u;
}
}
}
return crc ^ 4294967295u;
};
log("ComputeCrc32 Created");
Func<byte[], uint> ComputeAdler32 = buffer =>
{
const uint modulus = 65521u;
uint sumA = 1u;
uint sumB = 0u;
if (buffer == null || buffer.Length == 0)
{
return 1u;
}
for (int index = 0; index < buffer.Length; index++)
{
sumA = (sumA + buffer[index]) % modulus;
sumB = (sumB + sumA) % modulus;
}
return (sumB << 16) | sumA;
};
log("ComputeAdler32 Created");
Action<MemoryStream, byte[], byte[]> WritePngChunk = (stream, chunkType, chunkData) =>
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (chunkType == null || chunkType.Length != 4)
{
throw new ArgumentException(
"PNG chunk types must be exactly four bytes long.",
"chunkType"
);
}
byte[] safeChunkData = chunkData ?? new byte[0];
byte[] payloadLengthBytes = GetBigEndianBytes((uint)safeChunkData.Length);
stream.Write(payloadLengthBytes, 0, payloadLengthBytes.Length);
stream.Write(chunkType, 0, chunkType.Length);
if (safeChunkData.Length > 0)
{
stream.Write(safeChunkData, 0, safeChunkData.Length);
}
byte[] crcInput = new byte[chunkType.Length + safeChunkData.Length];
Buffer.BlockCopy(chunkType, 0, crcInput, 0, chunkType.Length);
if (safeChunkData.Length > 0)
{
Buffer.BlockCopy(safeChunkData, 0, crcInput, chunkType.Length, safeChunkData.Length);
}
byte[] crcBytes = GetBigEndianBytes(ComputeCrc32(crcInput));
stream.Write(crcBytes, 0, crcBytes.Length);
};
log("WritePngChunk Created");
Func<byte[], byte[]> CompressToZlib = buffer =>
{
byte[] safeBuffer = buffer ?? new byte[0];
byte[] deflateBytes = null;
using (MemoryStream compressedStream = new MemoryStream())
{
using (DeflateStream deflateStream = new DeflateStream(
compressedStream,
CompressionMode.Compress,
true))
{
deflateStream.Write(safeBuffer, 0, safeBuffer.Length);
}
deflateBytes = compressedStream.ToArray();
}
byte[] zlibPayload = new byte[2 + deflateBytes.Length + 4];
zlibPayload[0] = 120;
zlibPayload[1] = 156;
if (deflateBytes.Length > 0)
{
Buffer.BlockCopy(deflateBytes, 0, zlibPayload, 2, deflateBytes.Length);
}
byte[] adlerBytes = GetBigEndianBytes(ComputeAdler32(safeBuffer));
Buffer.BlockCopy(adlerBytes, 0, zlibPayload, 2 + deflateBytes.Length, adlerBytes.Length);
return zlibPayload;
};
log("CompressToZlib Created");
Func<Dictionary<string, BarcodeFormat>> GetSymbologyFormats = () =>
new Dictionary<string, BarcodeFormat>
{
{ "QR", BarcodeFormat.QR_CODE },
{ "MICROQR", BarcodeFormat.QR_CODE },
{ "DATAMATRIX", BarcodeFormat.DATA_MATRIX },
{ "CODE128", BarcodeFormat.CODE_128 },
{ "CODE39", BarcodeFormat.CODE_39 },
{ "AZTEC", BarcodeFormat.AZTEC },
{ "PDF417", BarcodeFormat.PDF_417 },
{ "EAN13", BarcodeFormat.EAN_13 },
{ "EAN8", BarcodeFormat.EAN_8 },
{ "UPCA", BarcodeFormat.UPC_A },
{ "CODABAR", BarcodeFormat.CODABAR },
{ "ITF", BarcodeFormat.ITF }
};
log("GetSymbologyFormats Created");
log(
$"Original Inputs -> Symbology: {symbology}, " +
$"DataLength: {(data != null ? data.Length.ToString() : "null")}, " +
$"Scale: {scale}"
);
symbology = string.IsNullOrEmpty(symbology) ? "QR" : symbology;
data = string.IsNullOrEmpty(data) ? "https://example.com" : data;
scale = scale <= 0m ? 1.0m : scale;
log(
$"Defaulted Inputs -> Symbology: {symbology}, " +
$"DataLength: {data.Length}, " +
$"Scale: {scale}"
);
log("Validating Inputs");
if (string.IsNullOrWhiteSpace(data))
{
throw new ArgumentException(
"The data string to encode cannot be null, empty, or whitespace.",
"data"
);
}
if (string.IsNullOrWhiteSpace(symbology))
{
throw new ArgumentException(
"The symbology definition must be provided.",
"symbology"
);
}
log("Inputs Validated Successfully");
log("Resolving Symbology");
string normalizedSymbology = symbology.Trim().ToUpperInvariant();
var symbologyFormats = GetSymbologyFormats();
BarcodeFormat format;
if (!symbologyFormats.TryGetValue(normalizedSymbology, out format))
{
throw new ArgumentException(
"Unsupported symbology: '" + symbology + "'. Supported values: " +
string.Join(", ", symbologyFormats.Keys) + ".",
"symbology"
);
}
log($"Resolved Symbology: {normalizedSymbology} to Format: {format}");
log("Configuring EncodingOptions");
var encodingOptions = new EncodingOptions
{
Width = 1,
Height = 1,
Margin = 0,
PureBarcode = true
};
log(
$"EncodingOptions set - Width: {encodingOptions.Width}, " +
$"Height: {encodingOptions.Height}, " +
$"Margin: {encodingOptions.Margin}, " +
$"PureBarcode: {encodingOptions.PureBarcode}"
);
if (normalizedSymbology == "MICROQR")
{
log("Applying MICROQR Version Hint");
encodingOptions.Hints[ZXing.EncodeHintType.QR_VERSION] = 1;
}
log("Initializing MultiFormatWriter");
var writer = new ZXing.MultiFormatWriter();
log("Calling MultiFormatWriter.encode...");
BitMatrix bitMatrix = writer.encode(
data,
format,
encodingOptions.Width,
encodingOptions.Height,
encodingOptions.Hints
);
if (bitMatrix == null)
{
throw new InvalidOperationException(
"ZXing MultiFormatWriter.encode returned null BitMatrix."
);
}
log($"BitMatrix Generated - Width: {bitMatrix.Width}, Height: {bitMatrix.Height}");
log("Setting up Raster Buffer Rendering");
int scaleFactor = Math.Max(1, (int)Math.Ceiling(scale));
int scaledWidth = bitMatrix.Width * scaleFactor;
int scaledHeight = bitMatrix.Height * scaleFactor;
int bytesPerPixel = 4;
int rgbaStride = scaledWidth * bytesPerPixel;
log(
$"Calculated Raster Bounds -> Width: {scaledWidth}, " +
$"Height: {scaledHeight}, " +
$"ScaleFactor: {scaleFactor}"
);
byte[] rgba = new byte[scaledWidth * scaledHeight * bytesPerPixel];
log($"Allocated RGBA Buffer -> Length: {rgba.Length} bytes");
for (int pixelOffset = 0; pixelOffset < rgba.Length; pixelOffset += bytesPerPixel)
{
rgba[pixelOffset] = 255;
rgba[pixelOffset + 1] = 255;
rgba[pixelOffset + 2] = 255;
rgba[pixelOffset + 3] = 255;
}
log("RGBA Buffer Cleared to White");
int paintedModules = 0;
for (int matrixY = 0; matrixY < bitMatrix.Height; matrixY++)
{
for (int matrixX = 0; matrixX < bitMatrix.Width; matrixX++)
{
if (!bitMatrix[matrixX, matrixY])
{
continue;
}
paintedModules++;
for (int offsetY = 0; offsetY < scaleFactor; offsetY++)
{
int pixelY = (matrixY * scaleFactor) + offsetY;
int rowOffset = pixelY * rgbaStride;
for (int offsetX = 0; offsetX < scaleFactor; offsetX++)
{
int pixelX = (matrixX * scaleFactor) + offsetX;
int modulePixelOffset = rowOffset + (pixelX * bytesPerPixel);
rgba[modulePixelOffset] = 0;
rgba[modulePixelOffset + 1] = 0;
rgba[modulePixelOffset + 2] = 0;
rgba[modulePixelOffset + 3] = 255;
}
}
}
}
log($"Raster Buffer Rendered - Painted {paintedModules} black modules");
log("Packing PNG Scanlines");
int scanlineLength = 1 + rgbaStride;
byte[] scanlines = new byte[scaledHeight * scanlineLength];
for (int row = 0; row < scaledHeight; row++)
{
int scanlineOffset = row * scanlineLength;
scanlines[scanlineOffset] = 0;
Buffer.BlockCopy(
rgba,
row * rgbaStride,
scanlines,
scanlineOffset + 1,
rgbaStride
);
}
log($"PNG Scanlines Packed -> Total Length: {scanlines.Length} bytes");
log("Beginning PNG Export to Base64");
byte[] pngSignature = new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 };
byte[] ihdrType = new byte[] { 73, 72, 68, 82 };
byte[] idatType = new byte[] { 73, 68, 65, 84 };
byte[] iendType = new byte[] { 73, 69, 78, 68 };
byte[] ihdrData = new byte[13];
byte[] widthBytes = GetBigEndianBytes((uint)scaledWidth);
byte[] heightBytes = GetBigEndianBytes((uint)scaledHeight);
Buffer.BlockCopy(widthBytes, 0, ihdrData, 0, widthBytes.Length);
Buffer.BlockCopy(heightBytes, 0, ihdrData, 4, heightBytes.Length);
ihdrData[8] = 8;
ihdrData[9] = 6;
ihdrData[10] = 0;
ihdrData[11] = 0;
ihdrData[12] = 0;
log("Compressing Scanlines via Zlib");
byte[] compressedScanlines = CompressToZlib(scanlines);
log($"Scanlines Compressed -> Zlib Payload Length: {compressedScanlines.Length} bytes");
using (MemoryStream pngStream = new MemoryStream())
{
pngStream.Write(pngSignature, 0, pngSignature.Length);
WritePngChunk(pngStream, ihdrType, ihdrData);
log("IHDR Chunk Written");
WritePngChunk(pngStream, idatType, compressedScanlines);
log("IDAT Chunk Written");
WritePngChunk(pngStream, iendType, new byte[0]);
log("IEND Chunk Written");
base64png = Convert.ToBase64String(pngStream.ToArray());
}
log("PNG Encoded to Base64 String");
log($"DataLength: {data.Length}");
log($"Scale: {scale} (Factor: {scaleFactor})");
log($"MatrixSize: {bitMatrix.Width}x{bitMatrix.Height}");
log($"ImageSize: {scaledWidth}x{scaledHeight}");
log($"Base64Length: {base64png.Length}");
log("Pipeline Completed Successfully");
}
catch (Exception ex)
{
msg += $"\r\n[FATAL ERROR] {ex.Message} \r\nStackTrace: {ex.StackTrace} § ";
log("Pipeline Execution Failed");
if (ex.InnerException != null)
{
msg += $"\r\n[INNER EXCEPTION] {ex.InnerException.Message} " +
$"\r\nStackTrace: {ex.InnerException.StackTrace} § ";
}
}
[Pipeline Initialized] § [GetBigEndianBytes Created] § [ComputeCrc32 Created] § [ComputeAdler32 Created] § [WritePngChunk Created] § [CompressToZlib Created] § [GetSymbologyFormats Created] § [Original Inputs → Symbology: DATAMATRIX, DataLength: 34, Scale: 5] § [Defaulted Inputs → Symbology: DATAMATRIX, DataLength: 34, Scale: 5] § [Validating Inputs] § [Inputs Validated Successfully] § [Resolving Symbology] § [Resolved Symbology: DATAMATRIX to Format: DATA_MATRIX] § [Configuring EncodingOptions] § [EncodingOptions set - Width: 1, Height: 1, Margin: 0, PureBarcode: True] § [Initializing MultiFormatWriter] § [Calling MultiFormatWriter.encode…] § [BitMatrix Generated - Width: 22, Height: 22] § [Setting up Raster Buffer Rendering] § [Calculated Raster Bounds → Width: 110, Height: 110, ScaleFactor: 5] § [Allocated RGBA Buffer → Length: 48400 bytes] § [RGBA Buffer Cleared to White] § [Raster Buffer Rendered - Painted 265 black modules] § [Packing PNG Scanlines] § [PNG Scanlines Packed → Total Length: 48510 bytes] § [Beginning PNG Export to Base64] § [Compressing Scanlines via Zlib] § [Scanlines Compressed → Zlib Payload Length: 627 bytes] § [IHDR Chunk Written] § [IDAT Chunk Written] § [IEND Chunk Written] § [PNG Encoded to Base64 String] § [DataLength: 34] § [Scale: 5 (Factor: 5)] § [MatrixSize: 22x22] § [ImageSize: 110x110] § [Base64Length: 912] § [Pipeline Completed Successfully] §
1KB at png encoding seems acceptable for a datamatrix.
EDIT: SSRS Supports VBA, so in theory you could build this out directly in SSRS/VBA as well, which would eliminate the need for BPM/ds modification in SSRS, as you could just call a function from an image expression. But, alas, i’m allergic to VBA.


