Makale Özeti

Bilhassa stok takip uygulamaları başta olmak üzere birçok uygulamada barkod bastırma ihtiyacımız olabilmektedir. Her ne kadar hazır barkod font'larını ekrana bastırmak ile bu özelliği sağlayabilsek de ben bu makalemde barkod'un .Net içerisinde bulunan classlar ile bir imaj olarak nasıl oluşturulabileceğimden bahsedeceğim. Bunun için en çok kullanılan ve her okuyucunun desteklediği Code39'u uygulamalarımızda kullanmamızı sağlayacak bir kontrol yazacağız.

Makale

         Merhabalar,

         Bilhassa stok takip uygulamaları başta olmak üzere birçok uygulamada barkod bastırma ihtiyacımız olabilmektedir. Her ne kadar hazır barkod font'larını ekrana bastırmak ile bu özelliği sağlayabilsek de ben bu makalemde barkod'un .Net içerisinde bulunan classlar ile bir imaj olarak nasıl oluşturulabileceğimden bahsedeceğim. Bunun için en çok kullanılan ve her okuyucunun desteklediği Code39'u uygulamalarımızda kullanmamızı sağlayacak bir kontrol yazacağız.

         Öncelikle Code39 barkod mantığını inceleyelim.

         Bu barkod sistemine Code39(3 Of 9) denmesinin sebebi 9 tane çizginden 3'ünün kalın diğerlerinin ince olmasıdır. Bu barkod sisteminde her karakter 9 tane çizgi ile temsil edilir. Bu çizgiler siyah, beyaz renklerinde ve kalın, ince tiplerinde olabilirler. Renk sıralaması Siyah, Beyaz, Siyah, Beyaz şeklinde standart bir şekilde ilerlerken kalın, ince çizgi sıralaması barkod'a yazılacak karakterlere bağlıdır. Bu karakterlere ait listeyi i:İnce k:Kalın olmak üzere aşağıda bulabilirsiniz.

Karakter Barkod Karakter Barkod Karakter Barkod Karakter Barkod
1 kiikiiiik B iikiikiik M kikiiiiki X ikiikiiik
2 iikkiiiik C kikiikiii i iiiikiikk Y kkiikiiii
3 kikkiiiii D iiiikkiik O kiiikiiki Z ikkikiiii
4 iiikkiiik E kiiikkiii P iikikiiki - ikiiiikik
5 kiikkiiii F iikikkiii Q iiiiiikkk . kkiiiikii
6 iikkkiiii G iiiiikkik R kiiiiikki BOŞLUK ikkiiikii
7 iiikiikik H kiiiikkii S iikiiikki * ikiikikii
8 kiikiikii I iikiikkii T iiiikikki $ ikikikiii
9 iikkiikii J iiiikkkii U kkiiiiiik / ikikiiiki
0 iiikkikii K kiiiiiikk V ikkiiiiik + ikiiikiki
A kiiiikiik L iikiiiikk k kkkiiiiii % iiikikiki

         Her karakteri nasıl barkod çizgilerine çevireceğimizi inceledik. Dikkat etmemiz gereken bazı noktalar var;

         a)Kalın, ince çizgi arasındaki oran 1:2 veya 1:3 olmalıdır.
         b)Karakterler arasında ince bir beyaz çizgi olmalıdır.
         c)Barkod'un başlangıç ve bitişinde * karakterleri olmalıdır.

         Kontrolümüzde oluşturulan barkodun ekranda gösterilmesini, print alınabilmesini ve resim dosyasına export edilebilmesini sağlayacağız. Şimdi kontrolümüzü yazmaya başlayabiliriz.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Imaging;
 
namespace Barcode
{
    public class Code39Control : Control
    {
        private ContextMenuStrip _ContextMenuStrip = new ContextMenuStrip();
        private int _WideNarrowRatio = 2;
        private Dictionary<string, byte[]> chars = new Dictionary<string, byte[]>();

         Öncelikle yazmış olduğumuz kontorlü Control class'ından inherit ediyoruz. Sonrasında ise kontrolümüzden kullanıcıların sağ tıklayarak resime veya printer'a çıktı alabilmeleri için bir ContextMenu oluşturuyoruz. Ayrıca belirttiğim gibi Kalın çizgilerle ince çizgiler arasındaki oranı bir property'e bağlıyoruz. Bu kısımda en önemli noktayı her bir karakterin ifade edileceği çizgiler gurubunu tutacağımız Dictionary nesnesi oluşturuyor. Bu nesne her bir string değer karşılığında bir byte dizisi tutmaktadır.
 

        public int WideNarrowRatio
        {
            get { return _WideNarrowRatio; }
            set { _WideNarrowRatio = value; }
        }
        public Code39Control()
        {
            _ContextMenuStrip.Items.Add("Export");
            _ContextMenuStrip.Items.Add("Print");
            this.ContextMenuStrip = _ContextMenuStrip;
            _ContextMenuStrip.ItemClicked += new ToolStripItemClickedEventHandler(_ContextMenuStrip_ItemClicked);
            this.BackColor = Color.White;
            this.TextChanged += new EventHandler(Code39Control_TextChanged);
            chars.Add("1", new byte[] { 1, 0, 0, 1, 0, 0, 0, 0, 1 });
            chars.Add("2", new byte[] { 0, 0, 1, 1, 0, 0, 0, 0, 1 });
            chars.Add("3", new byte[] { 1, 0, 1, 1, 0, 0, 0, 0, 0 });
            chars.Add("4", new byte[] { 0, 0, 0, 1, 1, 0, 0, 0, 1 });
            chars.Add("5", new byte[] { 1, 0, 0, 1, 1, 0, 0, 0, 0 });
            chars.Add("6", new byte[] { 0, 0, 1, 1, 1, 0, 0, 0, 0 });
            chars.Add("7", new byte[] { 0, 0, 0, 1, 0, 0, 1, 0, 1 });
            chars.Add("8", new byte[] { 1, 0, 0, 1, 0, 0, 1, 0, 0 });
            chars.Add("9", new byte[] { 0, 0, 1, 1, 0, 0, 1, 0, 0 });
            chars.Add("0", new byte[] { 0, 0, 0, 1, 1, 0, 1, 0, 0 });
            chars.Add("A", new byte[] { 1, 0, 0, 0, 0, 1, 0, 0, 1 });
            chars.Add("B", new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1 });
            chars.Add("C", new byte[] { 1, 0, 1, 0, 0, 1, 0, 0, 0 });
            chars.Add("D", new byte[] { 0, 0, 0, 0, 1, 1, 0, 0, 1 });
            chars.Add("E", new byte[] { 1, 0, 0, 0, 1, 1, 0, 0, 0 });
            chars.Add("F", new byte[] { 0, 0, 1, 0, 1, 1, 0, 0, 0 });
            chars.Add("G", new byte[] { 0, 0, 0, 0, 0, 1, 1, 0, 1 });
            chars.Add("H", new byte[] { 1, 0, 0, 0, 0, 1, 1, 0, 0 });
            chars.Add("I", new byte[] { 0, 0, 1, 0, 0, 1, 1, 0, 0 });
            chars.Add("J", new byte[] { 0, 0, 0, 0, 1, 1, 1, 0, 0 });
            chars.Add("K", new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 1 });
            chars.Add("L", new byte[] { 0, 0, 1, 0, 0, 0, 0, 1, 1 });
            chars.Add("M", new byte[] { 1, 0, 1, 0, 0, 0, 0, 1, 0 });
            chars.Add("N", new byte[] { 0, 0, 0, 0, 1, 0, 0, 1, 1 });
            chars.Add("O", new byte[] { 1, 0, 0, 0, 1, 0, 0, 1, 0 });
            chars.Add("P", new byte[] { 0, 0, 1, 0, 1, 0, 0, 1, 0 });
            chars.Add("Q", new byte[] { 0, 0, 0, 0, 0, 0, 1, 1, 1 });
            chars.Add("R", new byte[] { 1, 0, 0, 0, 0, 0, 1, 1, 0 });
            chars.Add("S", new byte[] { 0, 0, 1, 0, 0, 0, 1, 1, 0 });
            chars.Add("T", new byte[] { 0, 0, 0, 0, 1, 0, 1, 1, 0 });
            chars.Add("U", new byte[] { 1, 1, 0, 0, 0, 0, 0, 0, 1 });
            chars.Add("V", new byte[] { 0, 1, 1, 0, 0, 0, 0, 0, 1 });
            chars.Add("W", new byte[] { 1, 1, 1, 0, 0, 0, 0, 0, 0 });
            chars.Add("X", new byte[] { 0, 1, 0, 0, 1, 0, 0, 0, 1 });
            chars.Add("Y", new byte[] { 1, 1, 0, 0, 1, 0, 0, 0, 0 });
            chars.Add("Z", new byte[] { 0, 1, 1, 0, 1, 0, 0, 0, 0 });
            chars.Add("-", new byte[] { 0, 1, 0, 0, 0, 0, 1, 0, 1 });
            chars.Add(".", new byte[] { 1, 1, 0, 0, 0, 0, 1, 0, 0 });
            chars.Add(" ", new byte[] { 0, 1, 1, 0, 0, 0, 1, 0, 0 });
            chars.Add("*", new byte[] { 0, 1, 0, 0, 1, 0, 1, 0, 0 });
            chars.Add("$", new byte[] { 0, 1, 0, 1, 0, 1, 0, 0, 0 });
            chars.Add("/", new byte[] { 0, 1, 0, 1, 0, 0, 0, 1, 0 });
            chars.Add("+", new byte[] { 0, 1, 0, 0, 0, 1, 0, 1, 0 });
            chars.Add("%", new byte[] { 0, 0, 0, 1, 0, 1, 0, 1, 0 });
 
        }


         Yazmış olduğumuz kontrolün Constructor'unda öncelikle biraz önce oluşturduğumuz ContextMenu kontrolümüze Export ve Print adı altında 2 tane yeni Item atıyoruz ve nesnemizi kontrolümüzün ContextMenu'su olarak belirliyoruz. Daha sonrasında ise kullanıcı bu Item'lardan herhangi birine tıkladığında bunu yakalayabilmek adına ContextMenu'nun ItemClicked event'ını handle ediyoruz. Varsayılan olarak arka planın beyaz gelmesi için BackColor property'sine değerimizi atadıktan sonra kontrolümüzün Text property'si her değiştiğinde barkodun tekrar tekrar çizilmesi için TextChanged event'ını handle ediyoruz. Son olarak ise biraz önce oluşturmuş olduğumuz char property'sine çizgilerin kalınlık ve incelik durumlarını 1,0 lardan oluşan bir byte array şeklinde atıyoruz.
 

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            try
            {
                DrawBarcode(e.Graphics);
            }
            catch (Exception)
            {
                e.Graphics.DrawString("COULD NOT DRAW BARCODE", new Font("Times New Roman", 12), Brushes.Red, 0, 0);
            }
        }


         Bu kısımda ise kontrlümüzün OnPaint event'ını override ediyoruz ve bu event içerisinde biraz sonra yazacağımız DrawBarcode metodunun çalıştırılmasını, bu metod çalışırken oluşabilecek herhangi bir hatada ise ekrana Could Not Draw Barcode yazısının yazılmasını sağlıyoruz. Şimdi DrawBarcode metodunu inceleyelim.

        private void DrawBarcode(Graphics insGraphics)
        {
            string text = this.Text;
            if (!text.StartsWith("*")){text = "*" + text;}
            if (!text.EndsWith("*")){text = text + "*";}
            insGraphics.FillRectangle(new SolidBrush(this.BackColor), 0, 0, this.Width, this.Height);
            int narrowCount = 0;
            int wideCount = 0;
            int blankCount = 0;
            for (int i = 0; i < text.Length; i++)
            {
                byte[] insByteArray = chars[text.Substring(i, 1)];
                foreach (byte insByte in insByteArray)
                {
                    if (insByte == 1){wideCount++;}else{narrowCount++;}
                }
                if (i + 1 != text.Length){blankCount++;}
            }
            decimal widthPerUnit = Math.Round(Convert.ToDecimal(this.Width) / Convert.ToDecimal(((wideCount * _WideNarrowRatio) + blankCount + narrowCount)), 2);
            decimal currentLeft = 0;
            for (int i = 0; i < text.Length; i++)
            {
                byte[] insByteArray = chars[text.Substring(i, 1)];
                int index = 0;
                foreach (byte insByte in insByteArray)
                {
                    if (index % 2 == 0)
                    {
                        insGraphics.FillRectangle(new SolidBrush(this.ForeColor), (float)currentLeft, 0, (float)(insByte == 1 ? widthPerUnit * _WideNarrowRatio : widthPerUnit), this.Height);
 
                    }
                    currentLeft += (insByte == 1 ? widthPerUnit * _WideNarrowRatio : widthPerUnit);
                    index++;
                }
                currentLeft += widthPerUnit;
            }
        }


          Bu metodda öncelikle gelen metnin başında ve sonunda * karakterleri yoksa bu karakterleri ekliyoruz. Sonrasında kontrolün tüm arka planına arka plan renginde bir dikdörtgen çiziyoruz. Şimdi öncelikle barkod çizgilerimizin genişliğini ayarlayabilmek için kaç tane ince kaç tane uzun çizgi olduğunu sayıyoruz ve ayrıca kelimeler arasındaki boşluğu da sayıyoruz. Sonraki adımda ise kalın çizgilerimizi kısa çizgilere olan oranları ile çarpıyoruz, kısa çizgilerimiz ve kelimeler arası boşlukların sayısıyla topluyoruz. Bu değeri genişliğe böldüğümüzde bir kısa çizgiyi ne genişlikte çizmemiz gerektiğini bulacağız. Daha sonra aynı döngüyü tekrarlayarak kalın ve ince çizgilerimizden sadece siyah olanları kontrolümüzün ForeColor property'sinde tanımlı renge göre dikdörtgen olarak çiziyoruz. Burada önemli bir nokta beyaz çizgileri çizmiyoruz ancak her beyaz çizgi için bir sonraki siyah çizginin başlayacağı noktayı öteliyoruz. Bu işlem sonunda ise tüm barkodumuzu çizmiş oluyoruz.

        void Code39Control_TextChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        void _ContextMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem.Text == "Print")
            {
                PrintDocument p = new PrintDocument();
                p.PrintPage += new PrintPageEventHandler(p_PrintPage);
                p.Print();
            }
            else if (e.ClickedItem.Text == "Export")
            {
                _ContextMenuStrip.Close();
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.ShowDialog();
                if (sfd.FileName != "")
                {
                    Bitmap b = new Bitmap(this.Width, this.Height);
                    this.DrawToBitmap(b, new Rectangle(0, 0, this.Width, this.Height));
                    Image i =  (Image)b;
                    i.Save(sfd.FileName, ImageFormat.Jpeg);
                }
            }
        }
        void p_PrintPage(object sender, PrintPageEventArgs e)
        {
            Bitmap b = new Bitmap(this.Width, this.Height);
            this.DrawToBitmap(b, new Rectangle(0, 0, this.Width, this.Height));
            Image i = (Image)b;
            e.Graphics.DrawImage(i, new Point(10, 10));
 
        }
    }
}


         TextChanged event'ında kontrolün tekrar çizilmesini sağlıyoruz. ContextMenu'nun ItemClicked event'ında ise Print'e tıklandıysa PrintDocument kullanarak resmi yazdırıyoruz. Bunu yaparken kontrolü bitmap'e çevirip daha sonrasında image'e çeviriyoruz. Ve bu Image'i PrintDocument nesnesinin Event argumanlarından e içerisinde bulunan Graphics.DrawImage metoduna parametre vererek Print metodunun çalıştırılmasından sonra basılmasını sağlıyoruz. Eğer kullanıcı Export'u seçmiş ise bunu da Yine kontrolümüzden Image nesnesini oluşturduktan sonra bu nesnenin Save metodunu kullanarak bir dosyaya kaydettiriyoruz.

         Örnek bir uygulamayı ve kodları Download'lar kısmında bulabilirsiniz.

         Umarım Faydalı olmuştur.

         oztamer@hotmail.com
         tamer.oz@yazgelistir.com
         oztamer@hotmail.comOrnek Kodlar