Native 2D Barcodes support yet for Cloud?

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.

12 Likes