This project has moved. For the latest updates, please go here.

create valid barcode image

Nov 5, 2015 at 2:39 PM
Hello,

I'm trying to create an image with a type 128C barcode using Magick.NET-7.0.0.0021-Q8-x86. Whatever I try, I can not get the barcode recognized by a barcode scaner or zbarimg although, to the naked eye, the image looks similar to another image, for the same code, generated using System.Drawing.

I try to do this in Dynamics AX 2009 (ERP software) that has it's own language called x++ but it can use C# libraries (if added to references).

My code looks similar to what one normaly use in C# but with some differences. Maybe someone can take a look to see if I'm missing something to generate a valid barcode

first I declare the variables :
    str                              barcodetxt;
    InteropPermission       permission;

    ImageMagick.MagickImage image;
    ImageMagick.MagickColor bgColor, fontColor;
    ImageMagick.Gravity     gravity;

    System.Byte             r, g, b;
    System.Text             barcodeTxtNet;

    BarcodeCode128          MyBarcode = BarcodeCode128::construct();

    Image                   BarcodeImage;
    Int64                   barcodeBitmapPtr;
    System.Drawing.Bitmap   barcodeBitmap;
    Container               returnData;
;
 
now the code that generates the bitmap
    permission = new InteropPermission(InteropKind::ClrInterop); //this allows me to call C# code on the server tier
    permission .assert();

    r = System.Convert::ToByte(255);
    g = System.Convert::ToByte(255);
    b = System.Convert::ToByte(255);
    try
    {
        bgColor = new ImageMagick.MagickColor(r,g,b); //create a image with white background
        image = new ImageMagick.MagickImage(bgColor, 800, 240); //set the size

//next I try to set the bit depth to 1 but it dosn't seem to work 
//(if I save the image as a bmp it has bit depth of 32 and 8 if I save it as a jpg)
        image.set_ColorType(ImageMagick.ColorType::Bilevel);
        image.set_ClassType(ImageMagick.ClassType::Pseudo);
        image.ChangeColorSpace(ImageMagick.ColorSpace::RGB);

        barcodetxt = '6625020060338943108201500001061102';//this is the code

       //MyBarCode is a class that encodes the above code to code 128C
        MyBarCode.string(true,barcodetxt);
        MyBarCode.encode();
        barcodetxt=MyBarCode.barcodeStr();
        barcodetxt = strfmt('label:%1', barcodetxt);
// now barcodetext has this value: label:%"*"$%*!&&&%%&&)-!!#'%%-!')&#"""-&%&'!)%&&&%&"&#'""&&%*!&')!1
//if I copy this code in an word document and use the same font I get a valid barcode!

        r = System.Convert::ToByte(0);
        g = System.Convert::ToByte(0);
        b = System.Convert::ToByte(0);
        fontColor = new ImageMagick.MagickColor(r,g,b);

        image.set_Font(@'C:\WINDOWS\Fonts\C128N.ttf');
        image.set_FontPointsize(72);

        //image.set_BorderColor(bgColor);
        //image.set_BackgroundColor(bgColor);
        //image.set_FillColor(fontColor);
        //image.set_StrokeColor(ImageMagick.MagickColor::get_Transparent());
        //image.set_StrokeColor(bgColor);
        //image.set_StrokeWidth(0);
        //image.set_StrokeAntiAlias(false);

        gravity = ImageMagick.Gravity::Center;
        image.set_TextGravity(gravity);

        //image.set_TextKerning(1);
        //image.set_AntiAlias(false);
        //image.set_Depth(1);

        image.Read(barcodetxt);

        CodeAccessPermission::revertAssert();

        image.Write(@"c:\test.jpg"); 
      }
catch
{
...
}
thanks,
Alex
Coordinator
Nov 5, 2015 at 3:13 PM
Have you tried changing the output format to something else then JPEG? Does it work when you create the output with System.Drawing classes?
Nov 6, 2015 at 6:59 AM
I have tried with
please note bit depth is not 1 although I specifically set it; am I missing something?

this is the font I've used

here is the (correct) output of System.Drawing (cropped from print screen - it has numeric code also)

Unfortunately System.Drawing is not supported in a windows service; in my case it leaks GDI bitmap objects and it crashes when the limit is reached (10 thousands objects) and I have to restart ERP server (witch is a pain during business hours). By the way, do yo know if ImageMagick does have any problems when generating more than 100 thousands images at a time?
Coordinator
Nov 6, 2015 at 9:11 AM
I have no experience with barcode scanners but maybe your scanner needs the image at a certain size? In other words does it work when you increase the font size?

And you can use Magick.NET to create 100 thousands images at a time. But you might want to switch to the 64 bit version of Magick.NET to increase the amount of memory that you can allocate. When Magick.NET can no longer store the pixels of an image it will swap to disk. And this will not perform as good as when it can read the pixels from memory.
Nov 6, 2015 at 9:46 AM
I've changed the font size to 72 and I noticed that there are some grey shades around some bars and I think this is the reason the code is not recognized (it looks exactly the same with the one that is OK, except those grey shades; see here - try 400% zoom). Can you please tell me how to get rid of gray lines and how can I reduce the bit depth to 1?
Thank you,
Alex
Coordinator
Nov 6, 2015 at 10:16 AM
Can you try setting the AntiAlias property of MagickImage to false and the ColorType property to BiLevel?
Nov 6, 2015 at 10:22 AM
Allready did that:
    image.set_ColorType(ImageMagick.ColorType::Bilevel);
    image.set_ClassType(ImageMagick.ClassType::Pseudo);
    image.ChangeColorSpace(ImageMagick.ColorSpace::RGB);

    image.set_AntiAlias(false);
the image looks the same and has a bit depth of 8 if it's saved as a jpg and 32 if it's saved as png or bmp
Nov 6, 2015 at 10:45 AM
I've also tried
image.set_Depth(1);
but the bit depth doesn't change
Nov 6, 2015 at 11:27 AM
I stumbled uppon this page about converting images to 1 bit

the command that works is:
$ convert magick:wizard -monochrome -colors 2 monochrome-colors-2.bmp
$ identify monochrome-colors-2.bmp
monochrome-colors-2.bmp BMP 480x640 480x640+0+0 1-bit sRGB 2c 38.5KB 0.000u 0:00.000
but I can't seem to find how to set these options for ImageMagick.Image...
Coordinator
Nov 6, 2015 at 12:48 PM
-colors is the Quantize method of MagickImage. And you should set Colors value of QuantizeSettings to 2.

I will look into the add anti alias issue at a later moment.
Nov 6, 2015 at 1:04 PM
Unfortunately this doesn't work either...the file has bit depth of 32 and grey bars next to black ones: look here
        quantizeSettings = new ImageMagick.QuantizeSettings();
        quantizeSettings.set_Colors(2);
        image.Quantize(quantizeSettings);
I've also tried to create the image like this with the same result:
        readSettings = new ImageMagick.MagickReadSettings();
        readSettings.set_ColorSpace(ImageMagick.ColorSpace::sRGB);
        readSettings.set_Height(80);
        readSettings.set_Width(320);
        format = ImageMagick.MagickFormat::Bmp;
        readSettings.set_Format(format);
        readSettings.set_UseMonochrome(true);

        image = new ImageMagick.MagickImage("xc:white", readSettings);
do you have other ideas?
Coordinator
Nov 6, 2015 at 1:28 PM
What happens when you set the ColorSpace of the quantizeSettings to gray?
Nov 6, 2015 at 1:40 PM
same thing.

maybe I try too many combinations and I don't have the right one...

now I have
 readSettings = new ImageMagick.MagickReadSettings();
        readSettings.set_ColorSpace(ImageMagick.ColorSpace::sRGB);
        readSettings.set_Height(80);
        readSettings.set_Width(320);
        format = ImageMagick.MagickFormat::Bmp;
        readSettings.set_Format(format);
        readSettings.set_UseMonochrome(true);

        quantizeSettings = new ImageMagick.QuantizeSettings();
        quantizeSettings.set_Colors(2);
        colorSpace = ImageMagick.ColorSpace::Gray;
        quantizeSettings.set_ColorSpace(colorSpace);

        image = new ImageMagick.MagickImage("xc:white", readSettings);
        image.Quantize(quantizeSettings);
        
//do I still have to set these ?
        image.set_ColorType(ImageMagick.ColorType::Bilevel);
        image.set_ClassType(ImageMagick.ClassType::Pseudo);
Nov 9, 2015 at 7:55 AM
I've added
 image.get_Depth();
before
 image.Write(@"c:\test.bmp");
and returns 1 although the generated file has bit depth 32 according to windows
see here

and 8 according to identify
identify c:\test.bmp
c:\test.bmp BMP 240x100 240x100+0+0 8-bit sRGB 96.1KB 0.000u 0:00.000
if i remove
image.Read(barcodetxt);
then
 image.get_Depth();
returns 8 and identify (and windows) shows 1 bit depth
identify c:\test.bmp
c:\test.bmp BMP 240x100 240x100+0+0 1-bit sRGB 2c 3.35KB 0.000u 0:00.000
Of course, the resulted image is just a white background...

What else can I try?
Coordinator
Nov 9, 2015 at 8:39 AM
What is the value of image.get_TotalColors() for both examples?
Nov 9, 2015 at 9:07 AM
1 before image.Read(barcodetxt) and 7 after
Coordinator
Nov 9, 2015 at 9:36 AM
You need to reduce the number of colors to two after you have read the image to be able to save the image at 1 bit depth.

I have also figured out why setting anti-alias is ignored. But to fix this I will have to make a big change to the code of ImageMagick that will take around two days to complete. And since we have to do that in our spare time it might take a while before this is done.

There is however a work around for your situation. Since all your barcode images have the same size you can create an MagickImage with a fixed size and use the Drawable classes to draw your text on the image. I could post an example but you might want to give it a try yourself first.
Nov 9, 2015 at 12:04 PM
unfortunetley I can not get image.draw() to work.
        ...

        barcodetxt = '6625020060338943108201500001061102';
        MyBarCode.string(true,barcodetxt);
        MyBarCode.encode();
        barcodetxt=MyBarCode.barcodeStr();

        drawableFont = new ImageMagick.DrawableFont("BC C128 Narrow"); //,"normal",400,"normal");
        r = System.Convert::ToByte(0);
        g = System.Convert::ToByte(0);
        b = System.Convert::ToByte(0);
        fontColor = new ImageMagick.MagickColor(r,g,b);

        drawableStrokeColor = new ImageMagick.DrawableStrokeColor(fontColor);
        drawableText = new ImageMagick.DrawableText(10,10, barcodetxt);

        image.Draw(drawableStrokeColor,drawableFont, drawableText);
and I get
The class ImageMagick.MagickImage does not contain this function.
witch is, obviously, not true. My development evironment (called MorpX) throws this error whenever the parameters passed to a c# class/function are not correct or missing. Do you have an ideea what I'm missing?
Coordinator
Nov 9, 2015 at 12:31 PM
I am suspecting that MorpX does not understand params. You could try and put your 'drawables' in a list and call the overload that accepts an IEnumerable.
Nov 9, 2015 at 1:17 PM
I tried to define the list as:
  • System.Collections.ArrayList
  • ClrObject list = new ClrObject("System.Collections.Generic.List`1[System.String]");
but I have the same error when I compile the code.

I'll keep tring untill out of ideas and after that I'll patientley wait the fix you mention two posts ago :)
Thank you so much for your support!
Coordinator
Nov 9, 2015 at 1:27 PM
Maybe it works if you do list.AsEnumerable()?
Nov 9, 2015 at 2:04 PM
it doesn't work:
AsEnumerable is not a member of List`1
even if I don't put list.AsEnumerable() , my code does not compile at
image.Draw(list);
I have to find a way to define a list that draw() will accept as an argument...

I know it's hard for you to help me because of the differences between x++ and C# and I really appreciate your help but I don't want to bother you too much.