読者です 読者をやめる 読者になる 読者になる

バーコードライブラリ「Barcode Image Generation Library」に手を加えてみた

C#

MiBarcodeでも充分満足なのだが、スピードを言われてしまうと、自分のやり方では弱い。
別のライブラリを探したところ、「Barcode Image Generation Library」があったため、それに関するメモ。

調査

Code128に対応する、よさそうなバーコードライブラリがないかを探したところ、stackoverflowに情報が。
stackoverflow - C# : Generating Code 128 Barcode (width of bars/spaces)


その中のCode Projectのものがメンテナンスが続けられていて良さそうだったので、そちらを利用してみることに。
THE CODE PROJECT - Barcode Image Generation Library よりダウンロード。バージョンは「June 12, 2012 (1.0.0.13)」。



Barcode Image Generation Library のライセンス表記

記事のURL http://www.codeproject.com/Articles/20823/Barcode-Image-Generation-Library
著者 Brad Barnhill
参照記事バージョン 12 Jun 2012
ライセンス The Code Project Open License (CPOL) 1.02

 

利用してみての所感

  1. MiBarcodeに比べると、GUIが出てこない分、速い。
  2. クリップボード経由でのExcel2003へのデータ貼り付けが難しい。
  3. 追加コメントをバーコードにつけることができない。
  4. 追加コメントだけをバーコードにつけることができない。


いろいろとできそうだけれど、自分の希望の仕様(3,4を満たす)まであと少し。
ソースが公開されているのでソースを眺め、強引に手を加えることにした。



手を加えたところとソース

対象のクラスは「BarcodeLib.Barcode」のみであり、非常にやりやすかった。


プロパティを2つ追加。「追加コメント」と「追加コメントだけかどうかのbool」。

public string Comment { get; set; }
public bool CommentOnly { get; set; }


Encodeメソッドオーバーロードを追加し、上記で追加したプロパティ2つ分を引数に加えて実装

public Image Encode(TYPE iType, string StringToEncode, int Width, int Height, string comment, bool commentOnly)
{
    this.Comment = comment;
    this.CommentOnly = commentOnly;
    return Encode(iType, StringToEncode, Width, Height);
}


Encodeメソッド(引数なし版)に、追加コメントを引き渡す処理を追加(以下の★Add Start 〜 ★Add Endで囲んだ部分)。

this.Encoded_Value = ibarcode.Encoded_Value;
this.Raw_Data = ibarcode.RawData;

//  ★Add Start
if (CommentOnly)
{
    this.RawData = Comment;
}
else
{
    this.RawData += " " + Comment;
}
//  ★Add End

_Encoded_Image = (Image)Generate_Image();

 

結果

ビルドしてできたdllを参照・使用したところ、希望のモノができた。



使用してみたコード

仕様はMiBarcode版と同じだが、クリップボード経由でないため、
PNGファイルをローカル出力→PNGファイルを読込→Excel貼り付けとした。

public class Contents
{
    public string BarcodeValue { get; set; }
    public string Comment { get; set; }
}


/// <summary>
/// Excelへと出力
/// </summary>
/// <param name="contents">出力する内容</param>
/// <param name="commentOnly">コメントだけか</param>
/// <returns></returns>
private bool Export(List<Contents> contents,
                    bool commentOnly)
{
    //  Excelへの出力判定
    bool exported = false;

    //  Excelファイルが存在する場合、以前のデータは不要なため削除する
    if (System.IO.File.Exists(BarcodeSheetFullPath))
    {
        System.IO.File.Delete(BarcodeSheetFullPath);
    }

    Excel.Application app = new Excel.Application();
    Excel.Workbook workbook = app.Workbooks.Add();
    Excel.Worksheet sheet = (Excel.Worksheet)workbook.Sheets[1];

    Excel.Range cells = sheet.Cells;

    int rowIndex = 1;
    int printCount = 1;


    foreach (var content in contents)
    {
                
        //  Excel出力位置の調整
        //  Excelが横3列、縦13行で一ページであるため、
        //  セルを調整してバーコードを貼り付けていく
        Excel.Range range;
        int mod = printCount % 3;
        switch (printCount % 3)
        {
            case 1:
                range = (Excel.Range)cells[rowIndex, 1];
                break;

            case 2:
                range = (Excel.Range)cells[rowIndex, 4];
                break;

            case 0:
                range = (Excel.Range)cells[rowIndex, 7];
                if (rowIndex % 53 != 0)
                {
                    rowIndex = rowIndex + 4;
                }
                else
                {
                    //  改ページが必要な場合の設定
                    rowIndex = rowIndex + 7;
                }

                break;

            default:
                range = null;
                break;

        }

        printCount++;


        //  COMへの参照をなるべく早く解放したいため、
        //  ここでセルの位置を取得してしまう
        float fx = float.Parse(range.Left.ToString());
        float fy = float.Parse(range.Top.ToString());
                
        System.Runtime.InteropServices.Marshal.ReleaseComObject(range);
        range = null;

        //  バーコード出力するものがなければ、Excelの位置だけ調整して次のレコードへ
        //  *空白を設定する場合に使用する
        if (string.IsNullOrWhiteSpace(content.BarcodeValue))
        {
            continue;
        }


        //  バーコードシートに空白を設定することもあるため、
        //  バーコード出力するものがなければ、印刷処理はしない
        if (string.IsNullOrWhiteSpace(content.BarcodeValue)) { }
        else
        {
            SavePNGImageByBarcodeLib(content.BarcodeValue, content.Comment, commentOnly);

            //  Pictures.Insertは、Excel2010ではKB2396509 のような不具合があるため、
            //  Shapes.Addメソッドを使うしかないと思われる
            Excel.Shapes shapes = sheet.Shapes;
            Excel.Shape shape =
            shapes.AddPicture(PNGFullPath,
                                Microsoft.Office.Core.MsoTriState.msoFalse,
                                Microsoft.Office.Core.MsoTriState.msoTrue,
                                fx,
                                fy,
                                200, 70);

            //  サイズを戻す
            shape.ScaleHeight(1, Microsoft.Office.Core.MsoTriState.msoTrue);
            shape.ScaleWidth(1, Microsoft.Office.Core.MsoTriState.msoTrue);


            //  使用したCOMオブジェクトを解放
            System.Runtime.InteropServices.Marshal.ReleaseComObject(shape);
            shape = null;

            System.Runtime.InteropServices.Marshal.ReleaseComObject(shapes);
            shapes = null;
        }

    }


    //  保存するときはファイルフォーマットを指定すること
    //  指定しないと、正しいファイル定義ではない旨のエラーでExcelファイルを開けなくなる
    //  「いいえ」「キャンセル」の場合は例外を出してしまうため、try-catchしておく
    //  →例外であれば、キャンセルなどが選択されたとみなして、処理しない
    try
    {
        workbook.SaveAs(Filename: BarcodeSheetFullPath, FileFormat: 56);

        //  ここまででエラーが発生していないのであれば、
        //  出力はできたものと考える
        exported = true;
    }
    catch (System.Runtime.InteropServices.COMException)
    {
        //  ここでのエラーは、保存上書きで「いいえ」「キャンセル」を選択した時のものと考えられる
        //  そのため、続行して問題ない
        //  ただし、印刷していないことを知らせる
        exported = false;
    }
    catch (Exception)
    {
        //  上記以外の場合は原因を知りたいため、例外を飛ばす
        throw;
    }


    workbook.Close();
    app.Quit();

    System.Runtime.InteropServices.Marshal.ReleaseComObject(cells);
    cells = null;

    System.Runtime.InteropServices.Marshal.ReleaseComObject(sheet);
    sheet = null;

    System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
    workbook = null;

    System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
    app = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();


    return exported;
}


/// <summary>
/// バーコードデータイメージ(PNG)の作成
/// </summary>
/// <param name="barcodeValue"></param>
/// <param name="comment"></param>
private void SavePNGImageByBarcodeLib(string barcodeValue,
                                        string comment,
                                        bool commentOnly)
{
    BarcodeLib.Barcode lib = new BarcodeLib.Barcode();
    lib.IncludeLabel = true;

    if (string.IsNullOrWhiteSpace(comment))
    {
        lib.Encode(BarcodeLib.TYPE.CODE128A, barcodeValue, 202, 70);
    }
    else
    {
        lib.Encode(BarcodeLib.TYPE.CODE128A, barcodeValue, 202, 70, comment, commentOnly);
    }
    lib.SaveImage(PNGFullPath, BarcodeLib.SaveTypes.PNG);
}

 

最後に

作者のBrad Barnhillさんには本当に感謝です。ありがとうございます。