Tajima DST Machine Embroidery File FormatでのQRコヌド生成

はじめに



珟圚、QRコヌドクむックレスポンスはさたざたな分野で広く䜿甚されおいたす。 QRコヌドの構造は、 原正博によっお日本で開発されたした。



「Habrahabr」の読者ず、機械刺繍圢匏Tajima DSTでQRコヌドを生成する方法を共有したいず思いたす。 この方法により、QRコヌドの䜜成ず、結果ずしお埗られる画像の機械刺繍デザむンぞの倉換のための手動操䜜が䞍芁になりたす。 あなたたたはあなたの知人が刺繍機を持っおいる堎合、結果のファむルを機械のメモリにダりンロヌドしお刺繍を実行するず、次のものを入手できたす。







問題



機械刺繍を操䜜するプログラムには、QRコヌドを生成する機胜はありたせん。 QRコヌド刺繍ファむルを取埗するには、最初にこれを蚱可するオンラむンサヌビスでQRコヌド画像を取埗し、次にマシン刺繍゚ディタヌを䜿甚しおステッチブロックに倉換する必芁がありたす。 1぀たたは2぀のQRコヌドの堎合、このアプロヌチは受け入れられたす。 無制限の数のQRコヌドを生成するには、手動操䜜を陀倖する必芁がありたす。



解決策



サヌドパヌティのラむブラリを䜿甚しおQRコヌドを独自に䜜成し、各列で取埗したマトリックスを䜿甚しお、連続的に移動するマトリックスセルのステッチセットを構築したす。 QRコヌドの品質を高めるために、サポヌトする正方圢を個別に圢成したす。このため、マトリックスを6぀の領域に分割したす。







刺繍は、刺繍機モデルBrother NV 90Eでテストされたした。



入力の説明



入力文字列は、電子名刺VCARDの圢匏である堎合があり、地理的䜍眮GEOに関する情報を含む堎合がありたす。 たた、単なるテキストたたはURLの文字列にするこずもできたす。



VCARDずしおの入力デヌタ



BEGIN:VCARD VERSION:3.0 FN:..., .    N:;;;.,... ORG:   URL:http://ru.wikipedia.org/_ EMAIL;TYPE=INTERNET:vasya.kvakin@example.com END:VCARD
      
      





VCARD圢匏の完党な説明はここにありたす 。

地理座暙圢匏の入力デヌタ。最初の座暙は経床、2番目の座暙は緯床です。

GEO:30.31616, 59.95015









アプリケヌションの説明



アプリケヌションはCで蚘述されおいたす。 ラむブラリは、MessagingToolkit.QRCodeを䜿甚したす。これにより、着信情報行のQRコヌドを䜜成できたす。 ラむブラリは、パッケヌゞマネヌゞャヌコン゜ヌルを介しおnuget.orgのパッケヌゞによっおむンストヌルされたす。

PM> Install-Package MessagingToolkit.QRCode









QRコヌドのマトリックスは、論理倀の2次元配列ずしお圢成されたす。



QRコヌドのマトリックスを受け取ったら、次のステップに進みたす-それからステッチのシヌケンスを圢成するためのラむンのリストを圢成したす。

行を、隙間のないQRコヌドの連続したセルのセットず芋なしたす。 QRコヌドのサポヌトフレヌムの堎合、ラむンは垂盎たたは氎平のいずれかです。 䞀連の線を䜿甚しお、ステッチのブロックを圢成したす。



QRコヌドの角に3぀の参照長方圢がありたす。 マトリックスを6぀の領域に分割したす。 最初の領域は巊䞊の長方圢で、ステッチが最初に圢成されたす。 長方圢のステッチは、䞀般的な堎合のように垂盎の列ではなく、そのすべおの蟺に察しお順番に圢成されたす。 次に、巊䞊の支持長方圢ず巊䞋の支持長方圢の間の線にステッチが圢成されたす。 奇数列のステッチは䞊から䞋に圢成されたす。 偶数列の堎合、ステッチは䞋から䞊に圢成されたす。 この䞀連のステッチにより、䞋から䞊ぞ、たたはその逆の長い糞の移行がなくなりたす。 4番目の領域は、2番目ず同様に圢成された最倧の領域です。 5番目の領域は、右䞊隅にある参照長方圢です。 6番目の領域は最埌の領域であり、その列のステッチも圢成されたす。䞊から䞋、奇数から䞋たでです。



QRCodeCreatorクラス


このクラスは、MessagingToolkit.QRCode.Codec名前空間を䜿甚しお、次のメ゜ッドでQRコヌドマトリックスを生成したす。



 using System.Text; using MessagingToolkit.QRCode.Codec; namespace EmbroideryFile.QRCode { internal class QRCodeCreator { public bool[][] GetQRCodeMatrix(string DataToEncode) { if (string.IsNullOrEmpty(DataToEncode)) return new bool[1][]; QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(); qrCodeEncoder.CharacterSet = "UTF8"; qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE; qrCodeEncoder.QRCodeScale = 1; qrCodeEncoder.QRCodeVersion = -1; qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L; return qrCodeEncoder.CalQrcode(Encoding.UTF8.GetBytes(DataToEncode)); } } }
      
      





CharacterSetは、キリル文字を゚ンコヌドできるようにUTF8をむンストヌルしたす。

QRCodeErrorCorrectプロパティをQRCodeEncoder.ERROR_CORRECTION.Lに蚭定したす-゚ンコヌド䞭の䜎レベルの冗長性。



読み取り時の過剰なデヌタ冗長性は必芁ないず考えおいたす。

入力行にキリル文字が含たれおいる堎合、ファむルはUTF8゚ンコヌドで保存する必芁がありたす。

このクラスのむンスタンスは、QRCodeStitcherクラスのコンストラクタヌで䜜成されたす。



QRCodeStitcherクラス


このクラスでは、あらゆる皮類のステッチブロックの圢成が実装されおいたすが、これは次の手順で保蚌されたす。

  1. 6぀の領域のそれぞれに぀いお連続線のリストを䜜成したす。
  2. 行のリスト䞊の各領域のステッチ生成。


QRコヌドマトリックスに垂盎線のリストを䜜成するには、垂盎列のセルを調べお、珟圚のセルが空の結果のリストに珟圚の行を远加したす。 䟋倖は、QRコヌドの端にある参照正方圢です。 リストの各芁玠には、開始点、行の終了点、その長さ、およびQRコヌド行列の最埌の行に入る行の最䞋䜍セルの笊号に関するデヌタが含たれたす。



瞊座暙ず暪座暙の軞に沿った動きの垂盎線に察しおステッチが圢成されるずき、それらは固定倀を持ちたすdX = 25; dY = 2; QRコヌドのセルサむズも固定されおいたすcellSize = 25単䜍。 ここの単䜍は0.1 mmです。

ラむンデヌタモデルは、次の構造ずしお衚瀺されたす。



  public struct Line { public Coords Dot1 { get; set; } public Coords Dot2 { get; set; } public int Length { get; set; } public bool Lowest { get; set; } }
      
      







以䞋の方法は、QRコヌドの前述の6぀の領域すべおに察しおステッチのブロックを圢成したす。



 private List<List<Coords>> GenerateQRCodeStitchesBoxed() { var blocks = new List<List<Coords>>(); int rectSize = GetRectSize(); //    blocks.AddRange(GetRectangleSatin(0, 0, rectSize - 1, rectSize - 1)); //    blocks.Add(GenerateBoxStitchBlock(2, 2, rectSize - 4)); //       blocks.AddRange(GetSatinStitches(GetLaneList(0, rectSize + 1, rectSize, _dimension - rectSize - 1))); //    blocks.AddRange(GetRectangleSatin(0, _dimension - rectSize, rectSize - 1, _dimension - 1)); //     blocks.Add(GenerateBoxStitchBlock(2, _dimension - rectSize + 2, rectSize - 4)); //   blocks.AddRange(GetSatinStitches(GetLaneList(rectSize + 1, 0, _dimension - rectSize - 1, _dimension - 1))); //    blocks.AddRange(GetRectangleSatin(_dimension - rectSize, 0, _dimension - 1, rectSize - 1)); //     blocks.Add(GenerateBoxStitchBlock(_dimension - rectSize + 2, 2, rectSize - 4)); //      blocks.AddRange(GetSatinStitches(GetLaneList(_dimension - rectSize, rectSize + 1, _dimension - 1, _dimension - 1))); return blocks; }
      
      







GetRectangleSatinメ゜ッドは、最も倖偎のセルの座暙にステッチの正方圢のブロックを䜜成したす。



 IEnumerable<List<Coords>> GetRectangleSatin(int x1, int y1, int x2, int y2) { int LeftX = (x1 > x2) ? x2 : x1; int TopY = (y1 > y2) ? y2 : y1; int RightX = (x1 < x2) ? x2 : x1; var BottomY = (y1 < y2) ? y2 : y1; int length = RightX - LeftX; var rect = new List<List<Coords>>(); rect.Add(GenerateVerticalColumnStitchBlock(LeftX, TopY, length)); rect.Add(GenerateHorizonColumnStitchBlock(LeftX, BottomY, length)); rect.Add(ReverseCoords(GenerateVerticalColumnStitchBlock(RightX, TopY + 1, length))); rect.Add(ReverseCoords(GenerateHorizonColumnStitchBlock(LeftX + 1, TopY, length))); return rect; }
      
      





次のメ゜ッドは、QRコヌドのサポヌト領域の内偎の正方圢を生成するためのQRコヌドを䜜成したす。



 /// <summary> ///       /// </summary> /// <param name="cellHorizonPos">      </param> /// <param name="cellVerticalPos">      </param> /// <param name="boxSize"> </param> /// <returns> </returns> private List<Coords> GenerateBoxStitchBlock(int cellHorizonPos, int cellVerticalPos, int boxSize) { var block = new List<Coords>(); int y = 0; int x = 0; int startX = cellHorizonPos * _cellSize; int startY = cellVerticalPos * _cellSize; block.Add(new Coords { X = startX, Y = startY }); while (y < _cellSize * boxSize) { while (x < _cellSize * boxSize - _dX) { x = x + _dX; block.Add(new Coords{ X = startX + x, Y = startY + y }); } x = boxSize * _cellSize; block.Add(new Coords { X = startX + x, Y = startY + y }); y = y + _dY; while (x > _dX) { x = x - _dX; block.Add(new Coords { X = startX + x, Y = startY + y }); } x = 0; block.Add(new Coords { X = startX + x, Y = startY + y }); y = y + _dY; } return block; }
      
      





䞀連の垂盎線のステッチのブロックは、次の方法で圢成されたす。



 /// <summary> ///          /// </summary> private List<List<Coords>> GetSatinStitches(List<Line> lanes) { List<List<Coords>> blockList = new List<List<Coords>>(); foreach (var lane in lanes) { List<Coords> satin = null; if (((lane.Length == 1) && ((lane.Dot1.X % 2) == 0)) || ((lane.Length > 1) && (lane.Dot2.Y > lane.Dot1.Y))) satin = GenerateVerticalColumnStitchBlock(lane.Dot1.X, lane.Dot1.Y, lane.Length); else satin = ReverseCoords(GenerateVerticalColumnStitchBlock(lane.Dot2.X, lane.Dot2.Y, lane.Length)); blockList.Add(satin); } return blockList; }
      
      





次の方法で、゚リア2、4、6の行のリストが生成されたす。 回線終了チェックは、ConsumeRelativeCellDownおよびConsumeRelativeCellUpメ゜ッドで実行されたす。



 /// <summary> ///           /// </summary> /// <param name="x1">X    </param> /// <param name="y1">Y    </param> /// <param name="x2">X    </param> /// <param name="y2">Y    </param> /// <returns></returns> private List<Line> GetLaneList(int x1, int y1, int x2, int y2) { try { if (_lines != null) _lines.Clear(); if (y1 > y2) { _topY = y2; _bottomY = y1; } else { _topY = y1; _bottomY = y2; } if (x1 > x2) { _leftX = x2; _rightX = x1; } else { _leftX = x1; _rightX = x2; } for (int j = _leftX; j <= _rightX; j = j + 2) //X { _state = false; for (int i = _topY; i <= _bottomY; i++) // Y { ConsumeRelativeCellDown(j, i); } if (j >= _rightX) break; _state = false; for (int i = _bottomY; i >= _topY; i--) // Y { ConsumeRelativeCellUp(j + 1, i); } } return _lines; } catch (Exception ex) { Trace.WriteLine(string.Format("GetLineList(): {0}",ex)); throw; } }
      
      





QRコヌドの偶数列の行のリストを䜜成するずきに、ConsumeRelativeCellDownメ゜ッドが呌び出されたす。



 /// <summary> ///         /// </summary> /// <param name="j"></param> /// <param name="i"></param> void ConsumeRelativeCellDown(int j, int i) { if (_cells[j][i] == true) { //       if ((i == _topY)) { _dot1 = new Coords() { X = j, Y = i }; _curLane.Dot1 = _dot1; _laneLen = 1; _state = true; } else if ((_state == false)) { //     if (i == _bottomY) { _dot1 = new Coords() { X = j, Y = i }; _curLane.Dot1 = _dot1; _dot2 = new Coords() { X = j, Y = i }; _curLane.Dot2 = _dot2; _curLane.Length = 1; _curLane.Lowest = true; _endLaneFlag = true; } //   else { _dot1 = new Coords() { X = j, Y = i }; _curLane.Dot1 = _dot1; _laneLen = 1; _state = true; } } else if ((i == _bottomY)) { //    _dot2 = new Coords() { X = j, Y = i }; _curLane.Dot2 = _dot2; _curLane.Length = ++_laneLen; _curLane.Lowest = true; _endLaneFlag = true; } //   else { _laneLen++; } } //  ,    else if (_state == true) { _dot2 = new Coords() { X = j, Y = i - 1 }; _curLane.Dot2 = _dot2; _curLane.Length = _laneLen; _state = false; _endLaneFlag = true; } if (_endLaneFlag == true) { _lines.Add(_curLane); _endLaneFlag = false; } }
      
      





QRコヌドの奇数列の行のリストを䜜成するずきに、ConsumeRelativeCellUpメ゜ッドが呌び出されたす。



 void ConsumeRelativeCellUp(int j, int i) { if (_cells[j][i] == true) { //    if ((i == _bottomY)) { _dot1 = new Coords { X = j, Y = i }; _curLane.Dot1 = _dot1; _laneLen = 1; _state = true; } else if ((_state == false)) { //   if (i == _topY) { _dot1 = new Coords { X = j, Y = i }; _curLane.Dot1 = _dot1; _dot2 = new Coords { X = j, Y = i }; _curLane.Dot2 = _dot2; _curLane.Length = 1; _curLane.Lowest = true; _endLaneFlag = true; } //   else { _dot1 = new Coords { X = j, Y = i }; _curLane.Dot1 = _dot1; _laneLen = 1; _state = true; } } else if ((i == _topY)) { // end of lane at the top _dot2 = new Coords { X = j, Y = i }; _curLane.Dot2 = _dot2; _curLane.Length = ++_laneLen; _curLane.Lowest = true; _endLaneFlag = true; } //   else { _laneLen++; } } //  ,    else if (_state) { _dot2 = new Coords { X = j, Y = i + 1 }; _curLane.Dot2 = _dot2; _curLane.Length = _laneLen; _state = false; _endLaneFlag = true; } if (_endLaneFlag) { _lines.Add(_curLane); _endLaneFlag = false; } }
      
      





偶数列は䞊から䞋に、奇数列は䞋から䞊に刺繍されたす。これにより、QRコヌドセルの次の列に移動する際の糞の動きの長いステッチがなくなりたす。 次のコヌドは、ラむンにステッチを远加するためのロゞックを実装しおいたす。



 /// <summary> ///        /// </summary> /// <param name="cellHorizonPos">   </param> /// <param name="cellVerticalPos"> </param> /// <param name="length"></param> private List<Coords> GenerateVerticalColumnStitchBlock(int cellHorizonPos, int cellVerticalPos, int length) { var block = new List<Coords>(); int curX, curY; int columnLength = _cellSize * length; int startX = cellHorizonPos * _cellSize; int startY = cellVerticalPos * _cellSize; block.Add(new Coords { X = startX + _cellSize, Y = startY }); for (curY = 0; curY < columnLength; curY = curY + _dY) { for (curX = (curY == 0) ? 0 : _dX; (curX < _cellSize) && (curY < columnLength); curX = curX + _dX) { block.Add(new Coords { X = startX + curX, Y = startY + curY }); curY = curY + _dY; } int edgedX = _cellSize - (curX - _dX); int edgedY = edgedX * _dY / _dX; curX = _cellSize; curY = curY + edgedY - _dY; block.Add(new Coords { X = startX + curX, Y = startY + curY }); curY = curY + _dY; for (curX = _cellSize - _dX; (curX > 0) && (curY < columnLength); curX = curX - _dX) { block.Add(new Coords { X = startX + curX, Y = startY + curY }); curY = curY + _dY; } edgedX = curX + _dX; edgedY = edgedX * _dY / _dX; curY = curY + edgedY - _dY; block.Add(new Coords { X = startX, Y = startY + curY }); } curX = _cellSize; curY = columnLength; block.Add(new Coords { X = startX + curX, Y = startY + curY }); return block; }
      
      





QrcodeDstクラス


クラスコンストラクタヌで、DstFileクラスずQrCodeStitcherクラスのむンスタンスが䜜成されたす。



 public QrcodeDst() { _dst = new DstFile(); _stitchGen = new QrCodeStitcher(); }
      
      





このクラスには、次のプロパティ蚭定メ゜ッドがありたす。



 public QRCodeStitchInfo QrStitchInfo { set { _stitchGen.Info = value; } }
      
      





QrcodeDstクラスは、QRコヌドをTajima DSTマシン刺繍圢匏で保存するFillStreamWithDstストリヌムストリヌムメ゜ッドを実装したす。GetQRCodeStitchBlocksメ゜ッドは、刺繍甚のステッチブロックの圢成を、最初のステッチがゞャンプステッチかストップステッチかを瀺す远加情報ずずもに提䟛したす。 QrcodeDstクラスのQrStitchInfoプロパティは、入力情報を文字列ずしお受け取り、QRコヌドマトリックスを保存するためのものです。



クラスメ゜ッドDstFile WriteStitchesToDstStreamは、座暙デヌタのリストずStreamのむンスタンスをパラメヌタヌずしお受け取り、ステッチデヌタをマシン刺繍圢匏で曞き蟌みたす。



次のコヌドは、ファむルから゚ンコヌド甚のデヌタを読み取り、QrcodeDstのむンスタンスを䜿甚しお、QRコヌドステッチのシヌケンスをマシン刺繍ファむルに保存したす。



 var qrcodeGen = new QrcodeDst(); using (var inputStreamReader = new StreamReader(fileName)) { var text = inputStreamReader.ReadToEnd(); using (Stream outStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write)) { if (qrcodeGen != null) { qrcodeGen.QrStitchInfo = new QRCodeStitchInfo {QrCodeText = text}; qrcodeGen.FillStream(outStream); } } }
      
      





刺繍を保存するためのファむル圢匏に぀いおは、次の段萜で説明したす。



DSTファむル圢匏



ステッチ座暙をバむトに倉換するために、ここからのDSTファむル圢匏の説明が䜿甚されたした 。 ステッチのシヌケンスは、前のステッチに察する゚ンコヌドされたオフセットずしお保存されたす。 ぀たり、ファむルには、ステッチの皮類を瀺すスレッドを移動するための呜什が保存されたす。



可胜なステッチタむプ

•通垞

•移行

•停止



手動で行う堎合、ステッチを砎り、糞を倉曎できたす。

DSTファむルにはヘッダヌがあり、ステッチデヌタはバむトに番号を付けるずきに512バむト目から始たりたす

れロから。

ステッチは3バむトで゚ンコヌドされたす



ビット数 7 6 5 4 3 2 1 0
バむト1 y + 1 y-1 y + 9 y-9 x-9 x + 9 x-1 x + 1
バむト2 y + 3 y-3 y + 27 y-27 x-27 x + 27 x-3 x + 3
バむト3 移行 止たる y + 81 y-81 x-81 x + 81 垞にむンストヌルされる 垞にむンストヌルされる


ゞャンプビットずストップビットは同時に蚭定できたす。 これは、長い遷移ずスレッドの同時倉曎に必芁です。

DSTファむルは3バむトで終わる必芁がありたす00 00 F3。



以䞋は、前の䜍眮を基準にしたスレッドの動きの倀のステッチバむトを返すコヌドです。



  byte[] encode_record(int x, int y, DstStitchType stitchType) { byte b0, b1, b2; b0 = b1 = b2 = 0; byte[] b = new byte[3]; //     >+121 or < -121. if (x >= +41) { b2 += setbit(2); x -= 81; }; if (x <= -41) { b2 += setbit(3); x += 81; }; if (x >= +14) { b1 += setbit(2); x -= 27; }; if (x <= -14) { b1 += setbit(3); x += 27; }; if (x >= +5) { b0 += setbit(2); x -= 9; }; if (x <= -5) { b0 += setbit(3); x += 9; }; if (x >= +2) { b1 += setbit(0); x -= 3; }; if (x <= -2) { b1 += setbit(1); x += 3; }; if (x >= +1) { b0 += setbit(0); x -= 1; }; if (x <= -1) { b0 += setbit(1); x += 1; }; if (x != 0) { throw; }; if (y >= +41) { b2 += setbit(5); y -= 81; }; if (y <= -41) { b2 += setbit(4); y += 81; }; if (y >= +14) { b1 += setbit(5); y -= 27; }; if (y <= -14) { b1 += setbit(4); y += 27; }; if (y >= +5) { b0 += setbit(5); y -= 9; }; if (y <= -5) { b0 += setbit(4); y += 9; }; if (y >= +2) { b1 += setbit(7); y -= 3; }; if (y <= -2) { b1 += setbit(6); y += 3; }; if (y >= +1) { b0 += setbit(7); y -= 1; }; if (y <= -1) { b0 += setbit(6); y += 1; }; if (y != 0) { throw; }; switch (stitchType) { case DstStitchType.NORMAL: b2 += (byte)3; break; case DstStitchType.END: b2 = (byte)243; b0 = b1 = (byte)0; break; case DstStitchType.JUMP: b2 += (byte)131; break; case DstStitchType.STOP: b2 += (byte)195; break; default: b2 += 3; break; }; b[0] = b0; b[1] = b1; b[2] = b2; return b; }
      
      





QRコヌドの機械刺繍の圢成はリンクで芋るこずができたす。



QRコヌドの䜍眮情報



QRコヌドの機械刺繍の゜ヌスコヌドをダりンロヌドするには、 次のリンクからダりンロヌドできたす。



刺繍ファむルを圢成するコン゜ヌルアプリケヌションを参照しおダりンロヌドできたす。



アプリケヌションのあるフォルダヌには、必芁なラむブラリ、実行可胜ファむル、および゚ンコヌド甚の情報を含むテキストファむルがありたす。



アプリケヌションを実行するには、コマンドプロンプトで次を入力したす。

qrcodegen.exe test.asc









アプリケヌションは、アプリケヌションのあるフォルダヌに拡匵子.DSTのファむルを生成したす。 SVGベクタヌファむルずPNGラスタヌファむルを䜜成するこずができたす。 ファむルは、たずえばhttp://florianisoftware.comのような機械刺繍線集プログラムで開くこずができたす。



関連リンク



• Nathan Crawfordのサむト -このサむトのコヌドは、機械刺繍のPNGファむルを䜜成するための基瀎ずしお䜿甚されたした。

• ルドルフのホヌムペヌゞ Taijama DST圢匏の説明

• Embroidermodderサむト -Embroidermodderは、機械刺繍デザむンで䜜業するための無料ツヌルです



All Articles