2009-06-18 17:19:06 +00:00
|
|
|
/*
|
|
|
|
Embroidery Reader - an application to view .pes embroidery designs
|
|
|
|
|
2016-01-12 01:14:07 +00:00
|
|
|
Copyright (C) 2016 Nathan Crawford
|
2009-06-18 17:19:06 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
|
|
|
|
A copy of the full GPL 2 license can be found in the docs directory.
|
2009-08-17 18:53:06 +00:00
|
|
|
You can contact me at http://www.njcrawford.com/contact/.
|
2009-06-18 17:19:06 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Drawing;
|
2016-03-22 23:16:56 +00:00
|
|
|
using System.IO;
|
2009-06-18 17:19:06 +00:00
|
|
|
|
|
|
|
namespace PesFile
|
|
|
|
{
|
2016-03-22 23:48:13 +00:00
|
|
|
public class PECFormatException : System.Exception
|
|
|
|
{
|
|
|
|
public PECFormatException(string message) : base(message) { }
|
|
|
|
}
|
2013-12-07 00:02:34 +00:00
|
|
|
|
2009-06-18 17:19:06 +00:00
|
|
|
public class PesFile
|
|
|
|
{
|
2016-03-22 23:48:13 +00:00
|
|
|
private int imageWidth;
|
|
|
|
private int imageHeight;
|
|
|
|
private string _filename;
|
2013-12-07 00:03:40 +00:00
|
|
|
public List<StitchBlock> blocks = new List<StitchBlock>();
|
2015-04-03 02:25:27 +00:00
|
|
|
public List<Tuple<int, int>> colorTable = new List<Tuple<int, int>>();
|
2016-03-22 23:48:13 +00:00
|
|
|
private Int64 startStitches = 0;
|
|
|
|
private Point translateStart;
|
|
|
|
private UInt16 pesVersion;
|
2009-06-18 17:19:06 +00:00
|
|
|
|
|
|
|
|
2012-09-28 22:53:54 +00:00
|
|
|
// If set to true, this variable means we couldn't figure out some or
|
|
|
|
// all of the colors and white will be used instead of those colors.
|
2009-06-18 17:19:06 +00:00
|
|
|
private bool colorWarning = false;
|
|
|
|
|
|
|
|
private bool formatWarning = false;
|
|
|
|
|
|
|
|
public PesFile(string filename)
|
|
|
|
{
|
|
|
|
OpenFile(filename);
|
|
|
|
}
|
|
|
|
|
2013-12-04 19:43:50 +00:00
|
|
|
// Returns an Int16 representation of the 12 bit signed int contained in
|
|
|
|
// high and low bytes
|
|
|
|
private Int16 get12Bit2sComplement(byte high, byte low)
|
|
|
|
{
|
|
|
|
Int32 retval;
|
|
|
|
|
|
|
|
// Get the bottom 4 bits of the high byte
|
|
|
|
retval = high & 0x0f;
|
|
|
|
|
|
|
|
// Shift those bits up where they belong
|
|
|
|
retval = retval << 8;
|
|
|
|
|
|
|
|
// Add in the bottom 8 bits
|
|
|
|
retval += low;
|
|
|
|
|
|
|
|
// Check for a negative number (check if 12th bit is 1)
|
|
|
|
if ((retval & 0x0800) == 0x0800)
|
|
|
|
{
|
|
|
|
// Make the number negative by subtracting 4096, which is the
|
|
|
|
// number of values a 12 bit integer can represent.
|
|
|
|
// This is a shortcut for getting the 2's complement value.
|
|
|
|
retval -= 4096;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (Int16)retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a signed byte representation of the 7 bit signed int contained
|
|
|
|
// in b.
|
|
|
|
private SByte get7Bit2sComplement(byte b)
|
|
|
|
{
|
|
|
|
SByte retval;
|
|
|
|
|
2013-12-05 04:21:33 +00:00
|
|
|
// Ignore the 8th bit. (make sure it's 0)
|
2013-12-05 14:35:11 +00:00
|
|
|
b &= 0x7f;
|
2013-12-05 04:21:33 +00:00
|
|
|
|
2013-12-04 19:43:50 +00:00
|
|
|
// Check for a negative number (check if 7th bit is 1)
|
|
|
|
if ((b & 0x40) == 0x40)
|
|
|
|
{
|
|
|
|
// Make the number negative by subtracting 128, which is the
|
|
|
|
// number of values a 7 bit integer can represent.
|
|
|
|
// This is a shortcut for getting the 2's complement value.
|
|
|
|
retval = (SByte)(b - 128);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Positive number - no modification needed
|
|
|
|
retval = (SByte)b;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:19:06 +00:00
|
|
|
private void OpenFile(string filename)
|
|
|
|
{
|
2016-02-24 04:41:24 +00:00
|
|
|
_filename = filename;
|
|
|
|
|
2016-03-22 22:49:30 +00:00
|
|
|
// The using statements ensure fileIn is closed, no matter how the statement is exited.
|
2016-03-22 23:16:56 +00:00
|
|
|
// Open the file in read-only mode, but allow read-write sharing. This prevents a case where opening
|
|
|
|
// the file read-only with read sharing could fail because some other application already has it
|
|
|
|
// open with read-write access even though it's not writing to the file. (I suspect some antivirus
|
|
|
|
// programs may be doing this) Using this mode may allow reading half-written files, but I don't expect
|
|
|
|
// that will be an issue with PES designs, since they're generally written once when downloaded and left
|
|
|
|
// alone after that.
|
|
|
|
using (FileStream fileStreamIn = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
2016-02-24 04:41:24 +00:00
|
|
|
{
|
2016-03-22 23:16:56 +00:00
|
|
|
using (BinaryReader fileIn = new BinaryReader(fileStreamIn))
|
2009-06-18 17:19:06 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
string startFileSig = "";
|
|
|
|
for (int i = 0; i < 4; i++) // 4 bytes
|
2016-02-24 06:46:00 +00:00
|
|
|
{
|
2016-03-29 03:23:14 +00:00
|
|
|
// This needs to be read as a byte, since characters can be multiple bytes depending on encoding
|
|
|
|
startFileSig += (char)fileIn.ReadByte();
|
2016-02-24 06:46:00 +00:00
|
|
|
}
|
2016-03-22 22:49:30 +00:00
|
|
|
if (startFileSig != "#PES")
|
2016-02-24 04:41:24 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
// This is not a file that we can read
|
2016-03-22 23:48:13 +00:00
|
|
|
throw new PECFormatException("Missing #PES at beginning of file");
|
2016-02-24 04:41:24 +00:00
|
|
|
}
|
|
|
|
|
2016-03-22 22:49:30 +00:00
|
|
|
// PES version
|
|
|
|
string versionString = "";
|
|
|
|
for (int i = 0; i < 4; i++) // 4 bytes
|
2016-02-24 06:46:00 +00:00
|
|
|
{
|
2016-03-29 03:23:14 +00:00
|
|
|
// This needs to be read as a byte, since characters can be multiple bytes depending on encoding
|
|
|
|
versionString += (char)fileIn.ReadByte();
|
2016-02-24 06:46:00 +00:00
|
|
|
}
|
2016-03-22 22:49:30 +00:00
|
|
|
if (!UInt16.TryParse(versionString, out pesVersion))
|
2009-06-18 17:19:06 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
// This is not a file that we can read
|
2016-03-22 23:48:13 +00:00
|
|
|
throw new PECFormatException("PES version is not the correct format");
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
2016-03-22 22:49:30 +00:00
|
|
|
|
|
|
|
int pecstart = fileIn.ReadInt32();
|
|
|
|
// Sanity check on PEC start position
|
|
|
|
if (fileIn.BaseStream.Length < (pecstart + 532))
|
2016-02-24 04:41:24 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
// This file is probably truncated
|
2016-03-22 23:48:13 +00:00
|
|
|
throw new PECFormatException("File appears to be truncated (PEC section is beyond end of file)");
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
2012-08-21 20:05:41 +00:00
|
|
|
|
2016-03-22 22:49:30 +00:00
|
|
|
// Read number of colors in this design
|
|
|
|
fileIn.BaseStream.Position = pecstart + 48;
|
|
|
|
int numColors = fileIn.ReadByte() + 1;
|
|
|
|
List<byte> colorList = new List<byte>();
|
|
|
|
for (int x = 0; x < numColors; x++)
|
2016-02-24 04:41:24 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
colorList.Add(fileIn.ReadByte());
|
2016-02-24 04:41:24 +00:00
|
|
|
}
|
2016-03-22 22:49:30 +00:00
|
|
|
|
|
|
|
// Read stitch data
|
|
|
|
fileIn.BaseStream.Position = pecstart + 532;
|
|
|
|
bool thisPartIsDone = false;
|
|
|
|
StitchBlock curBlock;
|
|
|
|
int prevX = 0;
|
|
|
|
int prevY = 0;
|
|
|
|
int maxX = 0;
|
|
|
|
int minX = 0;
|
|
|
|
int maxY = 0;
|
|
|
|
int minY = 0;
|
|
|
|
int colorNum = -1;
|
|
|
|
int colorIndex = 0;
|
|
|
|
List<Stitch> tempStitches = new List<Stitch>();
|
|
|
|
while (!thisPartIsDone)
|
2016-02-24 04:41:24 +00:00
|
|
|
{
|
2016-03-22 22:49:30 +00:00
|
|
|
byte val1;
|
|
|
|
byte val2;
|
|
|
|
val1 = fileIn.ReadByte();
|
|
|
|
val2 = fileIn.ReadByte();
|
|
|
|
if (val1 == 0xff && val2 == 0x00)
|
|
|
|
{
|
|
|
|
//end of stitches
|
|
|
|
thisPartIsDone = true;
|
|
|
|
|
|
|
|
//add the last block
|
|
|
|
curBlock = new StitchBlock();
|
|
|
|
curBlock.stitches = new Stitch[tempStitches.Count];
|
|
|
|
tempStitches.CopyTo(curBlock.stitches);
|
|
|
|
curBlock.stitchesTotal = tempStitches.Count;
|
|
|
|
colorNum++;
|
|
|
|
colorIndex = colorList[colorNum];
|
|
|
|
curBlock.colorIndex = colorIndex;
|
|
|
|
curBlock.color = getColorFromIndex(colorIndex);
|
|
|
|
blocks.Add(curBlock);
|
|
|
|
}
|
|
|
|
else if (val1 == 0xfe && val2 == 0xb0)
|
|
|
|
{
|
|
|
|
//color switch, start a new block
|
|
|
|
|
|
|
|
curBlock = new StitchBlock();
|
|
|
|
curBlock.stitches = new Stitch[tempStitches.Count];
|
|
|
|
tempStitches.CopyTo(curBlock.stitches);
|
|
|
|
curBlock.stitchesTotal = tempStitches.Count;
|
|
|
|
colorNum++;
|
|
|
|
colorIndex = colorList[colorNum];
|
|
|
|
curBlock.colorIndex = colorIndex;
|
|
|
|
curBlock.color = getColorFromIndex(colorIndex);
|
|
|
|
//read useless(?) byte
|
|
|
|
// The value of this 'useless' byte seems to alternate
|
|
|
|
// between 2 and 1 for every other block. The only
|
|
|
|
// exception I've noted is the last block which appears
|
|
|
|
// to always be 0.
|
|
|
|
curBlock.unknownStartByte = fileIn.ReadByte();
|
|
|
|
blocks.Add(curBlock);
|
|
|
|
|
|
|
|
tempStitches = new List<Stitch>();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int extraBits1 = 0x00;
|
|
|
|
if ((val1 & 0x80) == 0x80)
|
|
|
|
{
|
|
|
|
// Save the top 4 bits to output with debug info
|
|
|
|
// The top bit means this is a 12 bit value, but I don't know what the next 3 bits mean.
|
|
|
|
// The only combinations I've observed in real files are 0x80, 0x90 and 0xa0. 0x80 is
|
|
|
|
// used for the bulk of stitches, with a few 0x80 and/or 0x90 in most files.
|
|
|
|
extraBits1 = val1 & 0xf0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deltaX = 0;
|
|
|
|
int deltaY = 0;
|
|
|
|
if ((val1 & 0x80) == 0x80)
|
|
|
|
{
|
|
|
|
// This is a 12-bit int. Allows for needle movement
|
|
|
|
// of up to +2047 or -2048.
|
|
|
|
deltaX = get12Bit2sComplement(val1, val2);
|
|
|
|
|
|
|
|
// The X value used both bytes, so read next byte
|
|
|
|
// for Y value.
|
|
|
|
val1 = fileIn.ReadByte();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is a 7-bit int. Allows for needle movement
|
|
|
|
// of up to +63 or -64.
|
|
|
|
deltaX = get7Bit2sComplement(val1);
|
|
|
|
|
|
|
|
// The X value only used 1 byte, so copy the second
|
|
|
|
// to to the first for Y value.
|
|
|
|
val1 = val2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int extraBits2 = 0x00;
|
|
|
|
if ((val1 & 0x80) == 0x80)
|
|
|
|
{
|
|
|
|
// Save the top 4 bits to output with debug info
|
|
|
|
// The top bit means this is a 12 bit value, but I don't know what the next 3 bits mean.
|
|
|
|
// In all the files I've checked, extraBits2 is the same as extraBits1.
|
|
|
|
extraBits2 = val1 & 0xf0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val1 & 0x80) == 0x80)
|
|
|
|
{
|
|
|
|
// This is a 12-bit int. Allows for needle movement
|
|
|
|
// of up to +2047 or -2048.
|
|
|
|
// Read in the next byte to get the full value
|
|
|
|
val2 = fileIn.ReadByte();
|
|
|
|
deltaY = get12Bit2sComplement(val1, val2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is a 7-bit int. Allows for needle movement
|
|
|
|
// of up to +63 or -64.
|
|
|
|
deltaY = get7Bit2sComplement(val1);
|
|
|
|
// Finished reading data for this stitch, no more
|
|
|
|
// bytes needed.
|
|
|
|
}
|
|
|
|
// Add stitch to list
|
|
|
|
tempStitches.Add(
|
|
|
|
new Stitch(
|
|
|
|
new Point(prevX, prevY),
|
|
|
|
new Point(prevX + deltaX, prevY + deltaY),
|
|
|
|
extraBits1,
|
|
|
|
extraBits2
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Calculate new "previous" position
|
|
|
|
prevX = prevX + deltaX;
|
|
|
|
prevY = prevY + deltaY;
|
|
|
|
|
|
|
|
// Update maximum distances
|
|
|
|
if (prevX > maxX)
|
|
|
|
{
|
|
|
|
maxX = prevX;
|
|
|
|
}
|
|
|
|
else if (prevX < minX)
|
|
|
|
{
|
|
|
|
minX = prevX;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevY > maxY)
|
|
|
|
{
|
|
|
|
maxY = prevY;
|
|
|
|
}
|
|
|
|
else if (prevY < minY)
|
|
|
|
{
|
|
|
|
minY = prevY;
|
|
|
|
}
|
|
|
|
}
|
2016-02-24 04:41:24 +00:00
|
|
|
}
|
2016-03-22 22:49:30 +00:00
|
|
|
imageWidth = maxX - minX;
|
|
|
|
imageHeight = maxY - minY;
|
|
|
|
translateStart.X = -minX;
|
|
|
|
translateStart.Y = -minY;
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int GetWidth()
|
|
|
|
{
|
|
|
|
return imageWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int GetHeight()
|
|
|
|
{
|
|
|
|
return imageHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
public string GetFileName()
|
|
|
|
{
|
|
|
|
if (_filename == null)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return _filename;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-07 00:14:15 +00:00
|
|
|
// Returns the path of the file it saved debug info to
|
|
|
|
public string saveDebugInfo()
|
2009-06-18 17:19:06 +00:00
|
|
|
{
|
2013-12-07 00:14:15 +00:00
|
|
|
string retval = System.IO.Path.ChangeExtension(_filename, ".txt");
|
|
|
|
System.IO.StreamWriter outfile = new System.IO.StreamWriter(retval);
|
2009-06-18 17:19:06 +00:00
|
|
|
outfile.Write(getDebugInfo());
|
|
|
|
outfile.Close();
|
2013-12-07 00:14:15 +00:00
|
|
|
return retval;
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public string getDebugInfo()
|
|
|
|
{
|
|
|
|
System.IO.StringWriter outfile = new System.IO.StringWriter();
|
|
|
|
outfile.WriteLine("PES header");
|
2012-09-28 22:53:54 +00:00
|
|
|
outfile.WriteLine("PES version:\t" + pesVersion);
|
2009-06-18 17:19:06 +00:00
|
|
|
|
|
|
|
outfile.WriteLine("stitches start: " + startStitches.ToString());
|
|
|
|
outfile.WriteLine("block info");
|
|
|
|
outfile.WriteLine("number\tcolor\tstitches");
|
|
|
|
for (int i = 0; i < this.blocks.Count; i++)
|
|
|
|
{
|
|
|
|
outfile.WriteLine((i + 1).ToString() + "\t" + blocks[i].colorIndex.ToString() + "\t" + blocks[i].stitchesTotal.ToString());
|
|
|
|
}
|
|
|
|
outfile.WriteLine("color table");
|
|
|
|
outfile.WriteLine("number\ta\tb");
|
|
|
|
for (int i = 0; i < colorTable.Count; i++)
|
|
|
|
{
|
2015-04-03 02:25:27 +00:00
|
|
|
outfile.WriteLine((i + 1).ToString() + "\t" + colorTable[i].Item1.ToString() + ", " + colorTable[i].Item2.ToString());
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
if (blocks.Count > 0)
|
|
|
|
{
|
|
|
|
outfile.WriteLine("Extended stitch debug info");
|
|
|
|
for (int blocky = 0; blocky < blocks.Count; blocky++)
|
|
|
|
{
|
2016-02-24 06:46:00 +00:00
|
|
|
outfile.WriteLine("block " + (blocky + 1).ToString() + " start (color index " + blocks[blocky].colorIndex + ")");
|
2013-12-07 00:14:15 +00:00
|
|
|
outfile.WriteLine("unknown start byte: " + blocks[blocky].unknownStartByte.ToString("X2"));
|
2009-06-18 17:19:06 +00:00
|
|
|
for (int stitchy = 0; stitchy < blocks[blocky].stitches.Length; stitchy++)
|
|
|
|
{
|
2016-02-24 06:46:00 +00:00
|
|
|
string tempLine = blocks[blocky].stitches[stitchy].a.ToString() + " - " + blocks[blocky].stitches[stitchy].b.ToString();
|
|
|
|
if(blocks[blocky].stitches[stitchy].extraBits1 != 0x00)
|
|
|
|
{
|
|
|
|
tempLine += " (extra bits 1: " + blocks[blocky].stitches[stitchy].extraBits1.ToString("X2") + ")";
|
|
|
|
}
|
|
|
|
if (blocks[blocky].stitches[stitchy].extraBits2 != 0x00)
|
|
|
|
{
|
|
|
|
tempLine += " (extra bits 2: " + blocks[blocky].stitches[stitchy].extraBits2.ToString("X2") + ")";
|
|
|
|
}
|
|
|
|
outfile.WriteLine(tempLine);
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
outfile.Close();
|
|
|
|
return outfile.ToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool getColorWarning()
|
|
|
|
{
|
|
|
|
return colorWarning;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool getFormatWarning()
|
|
|
|
{
|
|
|
|
return formatWarning;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Color getColorFromIndex(int index)
|
|
|
|
{
|
2012-09-28 22:23:10 +00:00
|
|
|
if(index >= 1 && index <= 64)
|
|
|
|
{
|
|
|
|
return Color.FromArgb(
|
2012-09-30 01:26:32 +00:00
|
|
|
PesColors.colorMap[index,0],
|
|
|
|
PesColors.colorMap[index,1],
|
|
|
|
PesColors.colorMap[index,2]
|
2012-09-28 22:23:10 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-10-10 21:25:23 +00:00
|
|
|
colorWarning = true;
|
2012-09-28 22:23:10 +00:00
|
|
|
return Color.White;
|
|
|
|
}
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
|
2015-04-03 06:09:59 +00:00
|
|
|
public Bitmap designToBitmap(Single threadThickness, bool filterUglyStitches, double filterUglyStitchesThreshold, float scale)
|
2009-06-18 17:19:06 +00:00
|
|
|
{
|
|
|
|
Bitmap DrawArea;
|
|
|
|
Graphics xGraph;
|
2015-04-03 06:09:59 +00:00
|
|
|
int imageWidth = (int)((GetWidth() + (threadThickness * 2)) * scale);
|
|
|
|
int imageHeight = (int)((GetHeight() + (threadThickness * 2)) * scale);
|
|
|
|
float tempThreadThickness = threadThickness * scale;
|
2009-06-18 17:19:06 +00:00
|
|
|
|
2013-12-07 00:05:15 +00:00
|
|
|
DrawArea = new Bitmap(imageWidth, imageHeight);
|
2013-12-11 00:33:45 +00:00
|
|
|
using (xGraph = Graphics.FromImage(DrawArea))
|
2013-12-07 00:05:15 +00:00
|
|
|
{
|
2015-04-03 06:09:59 +00:00
|
|
|
int translateX = (int)(translateStart.X * scale);
|
|
|
|
int translateY = (int)(translateStart.Y * scale);
|
|
|
|
xGraph.TranslateTransform(tempThreadThickness + translateX, tempThreadThickness + translateY);
|
2013-12-11 00:33:45 +00:00
|
|
|
|
|
|
|
// Draw smoother lines
|
2013-12-07 00:02:34 +00:00
|
|
|
xGraph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
2013-12-11 00:33:45 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < blocks.Count; i++)
|
2009-06-18 17:19:06 +00:00
|
|
|
{
|
2015-04-03 06:09:59 +00:00
|
|
|
using (Pen tempPen = new Pen(blocks[i].color, tempThreadThickness))
|
2013-12-07 00:02:34 +00:00
|
|
|
{
|
2013-12-11 00:33:45 +00:00
|
|
|
tempPen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
|
|
|
|
tempPen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
|
|
|
|
tempPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
|
|
|
|
|
|
|
|
foreach (Stitch thisStitch in blocks[i].stitches)
|
2013-12-07 00:02:34 +00:00
|
|
|
{
|
2013-12-11 00:33:45 +00:00
|
|
|
if (filterUglyStitches && // Check for filter ugly stitches option
|
|
|
|
!formatWarning && // Only filter stitches if we think we understand the format
|
|
|
|
thisStitch.calcLength() > filterUglyStitchesThreshold) // Check stitch length
|
|
|
|
{
|
|
|
|
// This stitch is too long, so skip it
|
|
|
|
continue;
|
|
|
|
}
|
2015-04-03 06:09:59 +00:00
|
|
|
Point tempA = new Point((int)(thisStitch.a.X * scale), (int)(thisStitch.a.Y * scale));
|
|
|
|
Point tempB = new Point((int)(thisStitch.b.X * scale), (int)(thisStitch.b.Y * scale));
|
|
|
|
xGraph.DrawLine(tempPen, tempA, tempB);
|
2013-12-07 00:02:34 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-17 03:20:19 +00:00
|
|
|
|
2009-06-18 17:19:06 +00:00
|
|
|
return DrawArea;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|