あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

【C#】Excelの取り扱いにClosedXMLを使用する

 今回はC#Excelを使用したい場合を考えたいと思います。2008年辺りまではCOMコンポーネントを使用してMicrosoft Excel 12.0 Object Libraryを参照し、COMオブジェクトの解放地獄でかなり苦しんでおられたのではないでしょうか。
 Office2007以降の場合、xlsx、xlsmファイルとなり内部的にはXML形式となりました。これによってCOMオブジェクトうを使用せずにExcelファイルを扱えるライブラリが色々公開されています。
 その中でClosedXMLをご紹介したいと思います。
 
1. Excelを扱うプロジェクトを作成します。
2. Visual Studioを起動し、「ツール」→「NuGet パッケージマネージャー」→「ソリューションの NuGet パッケージの管理」を選択します。
f:id:atamo_dev:20170719212412j:plain
3.「NuGet パッケージ管理ウィンドウ」で左のオンラインを選択します。
4. 右上オンラインの検索欄に「OpenXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212439j:plain
5. 表示された「DocumentFormat.OpenXml」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。
6. 右上オンラインの検索欄に「ClosedXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212451j:plain
7. 表示された「ClosedXML」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。

 これで前準備は完了しました。

github.comOpenXML SDK
github.comClosedXML


 以下Excelを扱ったサンプルクラスです。

using ClosedXML.Excel;
using System;
using System.IO;

namespace ExcelSample
{
  /// <summary>
  /// Excelの読み込みとワークシート、セルへのアクセスを行うクラス
  /// </summary>
  public class ExcelLoader : IDisposable
  {
    #region メンバ変数
    /// <summary>
    /// Excelのワークブック(2013以降のExcelを指定すること)
    /// </summary>
    private XLWorkbook _Workbook = null;
    #endregion

    #region プロパティ
    /// <summary>
    /// 全てのワークシートを取得します。
    /// </summary>
    public IXLWorksheets Worksheets
    {
      get
      {
        if (this._Workbook != null)
        {
          return this._Workbook.Worksheets;
        }
        else
        {
          return null;
        }
      }
    }
    #endregion

    #region コンストラクタ
    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    public ExcelLoader()
    {
    }

    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    public ExcelLoader(string path)
    {
      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
      }
    }
    #endregion

    #region 公開メソッド
    /// <summary>
    /// 解放処理
    /// </summary>
    public void Dispose()
    {
      CloseExcel();
    }

    /// <summary>
    /// 引数で指定されたExcelファイルを開きます。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public bool OpenExcel(string path)
    {
      CloseExcel();

      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
        return true;
      }
      else
      {
        return false;
      }
    }

    /// <summary>
    /// 指定したインデックスのワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="index">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, int index = 1)
    {
      if (this._Workbook == null)
      {
        return string.Empty;
      }

      try
      {
        var worksheet = this._Workbook.Worksheet(index);
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 指定したワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="worksheet">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, IXLWorksheet worksheet)
    {
      if (worksheet == null)
      {
        return string.Empty;
      }

      try
      {
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートのセルが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 現在オープンされているExcelファイルをクローズします。
    /// </summary>
    public void CloseExcel()
    {
      if (this._Workbook != null)
      {
        // 既にExcelが開かれている場合、破棄する
        this._Workbook.Dispose();
        this._Workbook = null;
      }
    }
    #endregion
  }
}

 クラスインスタンス生成時にExcelファイルのパスを指定し、Excelファイルからセルの読み込みを行う簡単なメソッドを実装したクラスです。
 COMオブジェクトの時代では速度面で遅く厳しいものがありましたが、ClosedXMLを使用した場合、速度もかなり速く利用を検討すべきだと思います。

イラストレーターで保存するとき「不明なエラーが発生しました」と出る!!保存できない人集合!!

イラストレーターで保存するとき「不明なエラーが発生しました」と出る!!保存できないじゃないか!!

という人向けの内容です!
私も出て困ったんですよねー、保存できないんですから。

 

そこで解決するために!最初はネットの情報にあったものを試してみました!

作業環境:Windows10、illustratorCC2017、メモリ8GBのデスクトップPC

 

イラレの環境ファイルを削除→PCを再起動
環境ファイルの場所は…
【users→ユーザー名→AppDate→Roaming→AdobeAdobe Illustrator 21 Settings→
ja_jp→x64→Adobe Illustrator Cloud Prefs】
Adobe Illustrator Cloud Prefsを削除する

別のサイトさんだと
【users→ユーザー名→AppDate→Roaming→AdobeAdobe Illustrator Settings→
ja_jp→x64→Adobe Illustrator Prefs】
Adobe Illustrator Prefsを削除する

でしたが、ファイルが見当たらなかったのでよく似たものを消してみました。
しかし直らないイラレが壊れることはありません)


・ファイルを作り直してコピーペーストする
直らなかった!

 

・バージョンを下げる
保存のバージョンを「illustrator CC→illustrator CS6」に変える
出なくなった!

 

・レイヤーのロックを外す
直る時と直らないときがある


(´・ω・`)え?分からないじゃん……

 

レイヤーの不具合じゃないかという話だけしか分かりませんでした。
が!作業の邪魔!なんとかしたい!って思ったので色々試しました。

とりあえず色々試したり調べたりして、回避できるかもしれない方法を見つけました。


多角形ツール+変形をして、その図形があるレイヤーをロック、または非表示にすると発生しました。
※あくまで自分の場合です

f:id:atamo_dev:20170714175640p:plain


多角形を作るだけならセーフでした。
でも、多角形作成後にその多角形の頂点や線をにゅーんと動かすとエラーが発生します

三角をよく多角形で作ってフキダシなんかを作る時に使っていました。
(次からは長方形ツールで作ろ……)

ただし、パスファインダーで合成してしまう、どこかの辺を消すなら問題ないです!
(その後変形しても問題なし)


あともう一つ試してみたのが、メモリが関係あるか
自分がいつも使っているPCは8GBです。

もう少しメモリの大きいPCでやったところ、エラーは発生しませんでした
もしかするとモリーの容量なのかも知れません。
実際のところ、原因って何なんだろう(´・ω・`)ウーン

 

多くのillustrator仲間の参考になると嬉しいです!

CocoaPodsでライブラリを公開する

プロジェクトを作成

まずはライブラリを作るためにプロジェクトを作成します。

XcodeでCreate new projectしてもいいのですが、CocoaPodsがテンプレートを公開しており、ターミナルから作成できるので今回はターミナルから作成していきます。

プロジェクト作成

以下のコマンドをターミナルで実行するとカレントディレクトリにプロジェクトが作成されます。

途中、幾つかの質問があるので、回答していきます。

pod lib create ライブラリ名

質問1 使用する言語はどちらですか?

What language do you want to use?? [ ObjC / Swift ]
> ObjC or Swift で回答

質問2 デモアプリを同梱しますか?

Would you like to include a demo application with your library? [ Yes / No ]
> Yes or No で回答

質問3 テストフレームワークを使いますか?

Which testing frameworks will you use? [ Quick / None ]
> Quick or None(使わない) で回答

質問4 Viewのテストを行いますか?

Would you like to do view based testing? [ Yes / No ]
> Yes or No で回答

成功するとXcodeが起動し、作成したプロジェクトが開きます。

ライブラリの作成

開いたプロジェクト内ソースツリーの[Pods]->[Development Pods]->[ライブラリ名]->[ライブラリ名]->[Classes]ReplaceMeというファイルがあるので、削除して自作ライブラリのファイルを配置します。

GitHubで公開

ライブラリのGitHubページを作成し、リポジトリのURLをコピーしておきます。

https://github.com/ユーザ名/ライブラリ名.git

プロジェクトファイル内のライブラリ名.podspecを編集します。

s.source: コピーしたリポジトリのURL

s.summary: 短い説明

s.description: 長い説明

#
# Be sure to run `pod lib lint ライブラリ名.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#

Pod::Spec.new do |s|
  s.name             = 'ライブラリ名'
  s.version          = '0.1.0'
  s.summary          = 'A short description of ライブラリ名.'

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC

  s.homepage         = 'https://github.com/ユーザ名/ライブラリ名'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'ユーザ名' => 'メールアドレス' }
  s.source           = { :git => 'https://github.com/ユーザ名/ライブラリ名.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '8.0'

  s.source_files = 'ライブラリ名/Classes/**/*'
  
  # s.resource_bundles = {
  #   'ライブラリ名' => ['ライブラリ名/Assets/*.png']
  # }

  # s.public_header_files = 'Pod/Classes/**/*.h'
  # s.frameworks = 'UIKit', 'MapKit'
  # s.dependency 'AFNetworking', '~> 2.3'
end

編集後、GitHubリポジトリにPushします。

Xcode上からSource Controlブランチ名Configure ライブラリ名を開き、RemoteからGitHubリポジトリを追加します。

Source ControlCommitを選択し、左下のPush to remoteへチェックを入れたらCommit Filesを押下します。

バージョンの指定

CocoaPods上でのバージョンはGitのタグに対応するので、ターミナルから公開時のバージョンをタグで付けます

git tag 1.0.0

リモートに反映します

git push 1.0.0

確認

podspecに誤りがないか確認します。

ターミナルでプロジェクトのディレクトリへ移動し、以下のコマンドを実行します。

pod lib lint

エラー場表示される場合は修正します。

(僕は説明が短すぎると言うエラーが出ました

CocoaPods trunkへ登録する

ターミナルでコマンドを実行します

pod trunk register 公開するメール '公開する名前' --description='説明'

入力したメールアドレスへ確認メールが来るので記載されているリンクを押下します。

ターミナル上で以下のコマンドを実行して名前が表示されていれば登録が完了しています。

pod trunk me

CocoaPods trunkへ登録します。

以下のコマンドを実行

pod trunk push ライブラリ名.podspec

pod try ライブラリ名 を実行してサンプルプロジェクトが開けば登録できています。

商用フリー 和柄パターン素材

 

f:id:atamo_dev:20170701161927p:plain

個人的に作成した和柄模様の素材です。

 

素材ファイルは下記URLに配置してあります。

https://drive.google.com/drive/folders/0B9dZ314mf8WoVGxla3hXeEVBSGc?usp=sharing

再配布以外でしたら個人用途に限りご自由にお使いください。

報告も、配布元の表示も不要です。

 

各素材とも下記2種類ずつあるので用途別にお使いいただければと思います。

Illustratorスウォッチ登録用aiファイル

Photoshopのパターン定義用にpngファイル

 

By SetJapanCorporation,Inc. Designer : すんすん。

【NW】名前解決って、なに?

「名前解決」・・・不思議な言葉ですよね。
この言葉ですぐわかる人は業界の人だけでしょう
ここでいう「名前」はインターネットURL、「解決」はIPアドレス検索、でしょうか
言い換えれば「インターネットURLからサーバのIPアドレスをさがす」イメージです。

皆さんがWebサイトなど見るときよくあるパターンは・・・
インターネットURLがLINEで来たり、QRコード読んだりして、
ブラウザでWebサイト見たりします
でも、見たいWebサイトが世界のどこにあるかは知りません。

Webサイトを公開するひとは、作ったら、どこかのWebサーバに格納します。
そして、このサーバはIPアドレスを持っています。

しかし、あなたWebサーバの間にはインターネットっていう空間がある・・・
ここをどうやってくっつけているのか、かなりざっくりと見てみます。

 

では、わかりやすくRPGにたとえてみましょう。
http://www.setjapan.co.jp」のWebサイトを見るというのは・・・
「setjapan.co.jp城にいるwww王http語を使って話したい」
という感じのクエストになります。

とりあえず、あなたは一番手近にいるDNSサーバってローカルな賢者に聞きます。
パソコンやらスマホやらに設定されているけど、大体は管理者が入れてるから、ほぼユーザは知らなくてよい話。

 

 あなたsetjapan.co.jp城www王話がしたいんすけど?
ローカル賢者.jpか。それなら賢者JPRSに聞くのじゃ。」

さすがはローカル賢者、なんも知りませんが、親切な彼は次の賢者を教えてくれます。
ちなみに”.jp”は、japanの意味で、JPRSが管理しているドメイン(TLD)です。

 

 あなたsetjapan.co.jp城ってどこすか?www王っています?
賢者JPRSsetjapan.co.jp城はこの場所にある。そこのNSというものに聞け」
どうやら、たらいまわしは賢者の得意技のようです。

場所は(なんとなく)わかったので、そこいってNSって人に聞きましょう。
このNSがsetjapan.co.jp内のIPアドレス(とか、諸々)の管理してます。

 

あなた「ここsetjapan.co.jp城っすか?www王っています?」
従者NSwww王はこの場所にいる。」と、王のIPアドレスを教えてくれます

やっと、王様に会えたので、http語で話しかけてみます。
あなた「王様、あのニュースどうなってんすか?」
www王「ほれ。こんな感じじゃ。うひゃひゃひゃw」
さすがwww王、名前通り草不可避です。

とまぁ、皆さんがWebを楽しんでる裏では
毎度こんな冒険が繰り広げられてるわけです。

 

でも、そうそううまくいかないこともあり
途中でどの賢者に聞いたらいいかわからなくなったり(ドメインサーバ不明)
王の場所分かったけどいなかったり(サーバダウン)
そもそも最初の賢者がいない(DNSサーバ未設定)
などをひっくるめて、「名前解決ができない」などと言ったりします。

なお。
説明の都合上、かなり端折ったり、デフォルメしていますので
もっとDNSサーバのことを知りたい人はSetJapanの門をたたいてみましょう。

 

【C#】デバッグ時に実行されるメソッドのトレースを出力する

 今回はC#デバッグ時に実行のトレースを行う方法を紹介します。用途としては非同期の場合にどこから呼出しされているか調査したいときなどに利用できるかと思います。
 方法としては2通りでCallerMemberNameAttributeクラスを利用する方法と、StackFrameクラスを利用する方法があります。

 以下はフォームにボタンのみを配置し、ボタンを押下すると出力ウィンドウへトレースの結果が出力されるサンプルとなっています。

デザイナー側実装

namespace DebugSample
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.button1 = new System.Windows.Forms.Button();
      this.SuspendLayout();
      // 
      // button1
      // 
      this.button1.Location = new System.Drawing.Point(84, 64);
      this.button1.Name = "button1";
      this.button1.Size = new System.Drawing.Size(75, 23);
      this.button1.TabIndex = 0;
      this.button1.Text = "出力";
      this.button1.UseVisualStyleBackColor = true;
      this.button1.Click += new System.EventHandler(this.button1_Click);
      // 
      // Form1
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(255, 146);
      this.Controls.Add(this.button1);
      this.Name = "Form1";
      this.Text = "Form1";
      this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Button button1;
  }
}


 実行サンプル用にボタンが配置してあるだけのウィンドウズフォームです。

コードビハインド側実装

using System;
using System.Windows.Forms;

namespace DebugSample
{
  /// <summary>
  /// サンプル用フォーム
  /// </summary>
  public partial class Form1 : Form
  {
    /// <summary>
    /// クラスの新しいインスタンスを生成します。
    /// </summary>
    public Form1()
    {
      InitializeComponent();
    }

    /// <summary>
    /// button1がクリックされたときに発生します。
    /// </summary>
    /// <param name="sender">呼び出し元オブジェクト</param>
    /// <param name="e">イベント引数</param>
    private void button1_Click(object sender, EventArgs e)
    {
      DebugUtil.DebugTrace("出力テスト");

      Console.WriteLine("");

      DebugUtil.DebugTrace(5);
    }
  }
}


 実行のトレース出力を行うためのユーティリティクラスです。

デバッグ用のユーティリティクラス実装

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;

namespace DebugSample
{
  /// <summary>
  /// デバッグ用のユーティリティクラス
  /// </summary>
  public static class DebugUtil
  {
    /// <summary>
    /// 呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="message">デバッグ出力するメッセージ</param>
    /// <param name="member">呼び出し元のメンバー</param>
    /// <param name="filePath">呼び出し元のファイルパス</param>
    /// <param name="line">呼び出し元の行番号</param>
    public static void DebugTrace(string message = "", [CallerFilePath] string sourceFile = "", [CallerLineNumber] int line = 0, [CallerMemberName] string member = "")
    {
      if (!String.IsNullOrEmpty(message)) { Console.WriteLine(String.Format("Message => {0} ", message)); }
      Console.WriteLine(String.Format("Source File Name => {0}", Path.GetFileName(sourceFile)));
      Console.WriteLine(String.Format("Source Directory Path => {0}", Path.GetDirectoryName(sourceFile)));
      Console.WriteLine(String.Format("Method Name => {0}", member));
      Console.WriteLine(String.Format("Line Number => {0}", line));
    }

    /// <summary>
    /// 指定したフレーム数の呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="outputLevel">スキップするスタック上のフレーム数</param>
    public static void DebugTrace(int skipFrames)
    {
      // フレーム数が0より小さい場合、処理を行わない
      if (skipFrames < 0) return;

      // フレームが1つ前になるまで出力する
      for (int i = skipFrames; 1 <= i; i--) { FrameTrace(i); }
    }

    /// <summary>
    /// 指定したフレーム数の呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="outputLevel">スキップするスタック上のフレーム数</param>
    private static void FrameTrace(int skipFrames)
    {
      var frame = new StackFrame(skipFrames);
      var method = frame.GetMethod();
      Console.WriteLine(String.Format("Method Name => {0}", method.ReflectedType.FullName + "." + method.Name));
    }
  }
}


 以下は出力結果です。

Message => 出力テスト 
Source File Name => Form1.cs
Source Directory Path => c:\Users\xxxxxx\Documents\Projects\DebugSample\DebugSample
Method Name => button1_Click
Line Number => 26

Method Name => System.Windows.Forms.Button.OnMouseUp
Method Name => System.Windows.Forms.Button.OnClick
Method Name => System.Windows.Forms.Control.OnClick
Method Name => DebugSample.Form1.button1_Click
Method Name => DebugSample.DebugUtil.DebugTrace

 ユーティリティクラスのDebugTraceメソッドでメッセージ引数を持つメソッドの場合、行番号までが出力されます。
 DebugTraceメソッドでフレーム数引数を持つメソッドの場合、名前空間.クラス.メソッド名で出力されます。

ポートフォリオの表紙の作り方!(テンション高め)

ハローこんにちは!初めまして!


突然ですが!今就活をしているデザイナーさんやイラストレーターさん向けに、ポートフォリオについてのお話をしようかと思います。
ポートフォリオ片手に?いやいや、お菓子やコーヒー片手に!
まったーりしながらお聞きくださいね。

あなたはポートフォリオをどのように作っていますか?
真っ白な背景に頑張って作った作品を並べて印刷!ハイ完成!
というのはやめましょう。
分かります、まる分かりです、時間なかったとかバイト忙しいとか言い訳です、世界は残酷です……。
でも、あなたの夢を目指す魂はそんなもので尽きませんよね!
「作品に心をこめて、全ての思いを相手に伝える」ポートフォリオを作りましょう!


……いろいろ言いたいことはありますが、まずは一個だけ。


表紙には命をかける!


これです。ハイ。

……正直、文字って読むのが面倒なんですよねー。
文字の集合体を見ると、拒絶反応が起きますね!
もっとわかりやすくしてほしいなー……。
って思った私が、表紙を作っちゃいました。

 

ポイントとしては……

表紙は見られるか見られないかということも関わる顔の役目なので、いい作品を持ってくること。

ただし、全力を出すのはだめですよ?
全力を出せば、それ以上見る意味が無くなりますから。
そこで「チラ見(試し読み)」のような手段を使います。
「続きを見なきゃ!気になる!」って思わせる方法です。
ここでレイアウトが役に立ちます。
いい作品をチラ見させ、あえて全体が見えないようにする。
パッと見てまとまりがあるうえ、綺麗に整頓されていることで上級感を出します。
項目ごとのピックアップをひとつづつ……だとさらにいいと思いますよ!

 

f:id:atamo_dev:20170602181514p:plain


そんな感じで実際に創った表紙がこれです。

何が出来るの?っていうのが一発で分かるけど、細かいところは中じゃないと分からないっていうのがいいですよっ!


どうですか?

めくってみたくなるでしょう?