DataMatrix.Net ported to Compact Framework

Print This Post Print This Post

(Updated 28. april 2010: see bottom)

If you need to print, show, generate or analyse DataMatrix Barcodes on a Windows Mobile device, you can now use this class library. I have ported the code to be compatible with Compact Framework 2.0 and Visual Studio 2005.

The original full .NET framework source code is located at SourceForge.

Here is first a screenshot of the test application running on a Windows Mobile device using the DataMatrixNetCF class:

Test application screenshot

The full .NET framework has much more functions or the classes provide more optional arguments than Compact Framework (CF) does. So there some code to be changed to work with CF. BTW: you can run the code on a desktop PC to, as the Full Framework is upwards compatible to CF.

I had to change some constructs which are used initialize a structure directly with some values. Here is one example for DmtxDecode.cs:

Original:

            DmtxPixelLoc pEmpty = new DmtxPixelLoc() { X = 0, Y = 0 };

Visual Studio 2005 / Compact Framework 2:

            DmtxPixelLoc pEmpty = new DmtxPixelLoc();
            pEmpty.X = 0; pEmpty.Y = 0;

Similar changes have to be applied to a lot of code lines:
Original:

    follow.Loc = new DmtxPixelLoc() { X = followBeg.Loc.X + DmtxConstants.DmtxPatternX[patternIdx], Y = followBeg.Loc.Y + DmtxConstants.DmtxPatternY[patternIdx] };

Visual Studio 2005 / Compact Framework 2:

    follow.Loc = new DmtxPixelLoc(followBeg.Loc.X + DmtxConstants.DmtxPatternX[patternIdx], followBeg.Loc.Y + DmtxConstants.DmtxPatternY[patternIdx]);

To get this working, the structure defined in DmtxPixelLoc.cs had to get a constructor code:

        public DmtxPixelLoc(int x, int y)
        {
            _x = x;
            _y = y;
        }

As the compiler complained about this ugly contruct, I rewrote this:

    prevPrevValue = (byte)((prevIndex > channel.FirstCodeWord / 12) ? channel.EncodedWords[prevIndex - 1] : 0);

to this

    if (prevIndex > channel.FirstCodeWord / 12)
       prevPrevValue = channel.EncodedWords[prevIndex - 1];
    else
       prevPrevValue = 0;

I dont like this short forms of If/else.

Finally it took some time to convert this code of the file DmtxImageEncoder.cs to CF:

        internal static Bitmap CopyDataToBitmap(byte[] data, int width, int height)
        {
            data = InsertPaddingBytes(data, width, height, 24);
            int stride = 4 * ((width * 24 + 31) / 32);
            GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
            //Here create the Bitmap to the know height, width and format
            Bitmap bmp = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, dataHandle.AddrOfPinnedObject());
            return bmp;
        }

In compact framework this works:

        internal static Bitmap CopyDataToBitmap(byte[] data, int width, int height)
        {
            data = InsertPaddingBytes(data, width, height, 24);
            int stride = 4 * ((width * 24 + 31) / 32);
            GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);

            // Create a new bitmap.
            Bitmap msBMP = new Bitmap(width,height,PixelFormat.Format24bppRgb);

            // Lock the bitmap's bits.
            Rectangle rect = new Rectangle(0, 0, msBMP.Width, msBMP.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                msBMP.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);

            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;

            int bytes  = bmpData.Stride * msBMP.Height;
            // Copy the RGB values back to the bitmap
            System.Runtime.InteropServices.Marshal.Copy(data, 0, ptr, bytes);

            // Unlock the bits.
            msBMP.UnlockBits(bmpData);
            return msBMP; // return bmp;
        }

Here you can download the source code of the class library and a test application. The code is written in Visual Studio 2005 with Windows Mobile 5 SDK as target: [Download not found]

If you need some PDF library for Windows Mobile, see my port of iTextSharp. The sourceforge DataMatrixNet code uses iTextSharp too.

Update 28.  april 2010:

There was a question at CodeProject about ECC200 compatibilty and a barcode test application called bcTester, that does not accept the barcodes generated with this sample app.

So I took a deeper look at the library and found, that my default datamatrixnet options dont fit what bcTester likes. So I changed the code of the sample application and it now offers a Settings dialog:

The main changes are the default options:

            options.ModuleSize = 4;
            options.MarginSize = 4;
            options.BackColor = Color.White;
            options.ForeColor = Color.Black;
            options.SizeIdx = DmtxSymbolSize.DmtxSymbol32x32;// DmtxSymbol96x96;
            options.Scheme = DmtxScheme.DmtxSchemeAscii;// DmtxSchemeAutoBest;

Another nice new feature (I think) is that you can use \xHH (HH=hex byte value) to encode control characters. Here is the string parser, that translates the mixed string to byte[]:

        public static byte[] FromHexedString(string val){ 
            //replace \xHH with char of before using getbytes
            int iPos = val.IndexOf("\\x");
            while(iPos>=0){
                string s = val.Substring(iPos, 4);
                byte b = byte.Parse(val.Substring(iPos+2,2), NumberStyles.HexNumber);
                //string c = Convert.ToString(b,16);
                char ch = (char)b;
                //test
                //byte[] bTest = Encoding.ASCII.GetBytes(ch.ToString());
                //System.Diagnostics.Debug.WriteLine(string.Format("Encoded {0:x} as '{1}'", bTest,ch));
                string o = val.Substring(0, iPos) + ch + val.Substring(iPos + 4);
                val = o;
                iPos = val.IndexOf("\\x");
            }
            byte[] valAsByteArray = Encoding.ASCII.GetBytes(val);
            return valAsByteArray;
        }

I extended my lib HexEncoding.cs to be able to do so. After all, bcTester accepts the barcode:


Download new version: [Download not found]

One Comment

  1. josef says:

    Transfered my last response from http://www.codeproject.com/Articles/66495/DataMatrixNet-ported-to-Compact-Framework.aspx?msg=3456058

    ECC200 Datamatrix is the way to encode data into a dot pattern which conforms to ECC200 (the error correction) datamatrix barcode.

    Fortunately DatamatrixNet and DatamatrixNetCF are fully compatible to create such barcodes.

    GS1 stands for a way to arrange data, which then can be encoded into code128 or datamatrix. GS1 only defines the data scheme!

    I took the examples from the GS1 datamatrix introduction … http://www.gs1.org/docs/barcodes/GS1_DataMatrix_Introduction_and_technical_overview.pdf%5B^].

    I used all four samples in the pdf, extracted the images and compared the results with the ones from my sample DatamatrixNetCF application. Everything works OK. bcTester tends to warn you, if you use human-readable FNC1 and GS encoding, but the results for the barcode decoding in bcTester where the same.

    You know, that you can use “]d2” for and “]d1” for . This can be used in DatamatrixNetCF too. But you can also used the hex encoding I implemented in the actual version of my app (see my web site). So you can use \x86 for and \x1d for .

    For the doc example 4.3.2-1 you can use this line to create the same datamatrix data as in the book:

    \x8602034531200000111709112510ABCD1234\x1d3710

    or

    ]d202034531200000111709112510ABCD1234]d13710

    I needed to get more background on all this, but I am sure, you already knew this all.

Leave a Reply