private void OpenFile(string filename) { _filename = filename; // The using statements ensure fileIn is closed, no matter how the statement is exited. // 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)) { using (BinaryReader fileIn = new BinaryReader(fileStreamIn)) { string startFileSig = ""; for (int i = 0; i < 4; i++) // 4 bytes { // This needs to be read as a byte, since characters can be multiple bytes depending on encoding startFileSig += (char)fileIn.ReadByte(); } if (startFileSig != "#PES") { // This is not a file that we can read throw new PECFormatException("Missing #PES at beginning of file"); } // PES version string versionString = ""; for (int i = 0; i < 4; i++) // 4 bytes { // This needs to be read as a byte, since characters can be multiple bytes depending on encoding versionString += (char)fileIn.ReadByte(); } if (!UInt16.TryParse(versionString, out pesVersion)) { // This is not a file that we can read throw new PECFormatException("PES version is not the correct format"); } int pecstart = fileIn.ReadInt32(); // Sanity check on PEC start position if (fileIn.BaseStream.Length < (pecstart + 532)) { // This file is probably truncated throw new PECFormatException("File appears to be truncated (PEC section is beyond end of file)"); } // 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++) { colorList.Add(fileIn.ReadByte()); } // 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>(); Stitch prevStitch = null; bool firstStitchOfBlock = true; while (!thisPartIsDone) { 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 start with 2 for the first block and // alternate between 2 and 1 for every other block after that. The only exception // I've noted is the last block which appears to always be 0. curBlock.unknownStartByte = fileIn.ReadByte(); blocks.Add(curBlock); firstStitchOfBlock = true; tempStitches = new List<Stitch>(); } else { int deltaX = 0; int deltaY = 0; int extraBits1 = 0x00; Stitch.MoveBitSize xMoveBits; Stitch.MoveBitSize yMoveBits; 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 0x10 and 0x20. 0x20 occurs // about 4 times as much as 0x10 in the samples I have available. extraBits1 = val1 & 0x70; // This is a 12-bit int. Allows for needle movement // of up to +2047 or -2048. deltaX = get12Bit2sComplement(val1, val2); xMoveBits = Stitch.MoveBitSize.TwelveBits; // 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); xMoveBits = Stitch.MoveBitSize.SevenBits; // 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 & 0x70; // 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); yMoveBits = Stitch.MoveBitSize.TwelveBits; } else { // This is a 7-bit int. Allows for needle movement // of up to +63 or -64. deltaY = get7Bit2sComplement(val1); yMoveBits = Stitch.MoveBitSize.SevenBits; // Finished reading data for this stitch, no more // bytes needed. } Stitch.StitchType stitchType; if (deltaX == 0 && deltaY == 0) { // A stitch with zero movement seems to indicate the current and next stitches are movement only. // Almost always occurs at the end of a block. stitchType = Stitch.StitchType.MovementBeginAnchor; } else if (extraBits1 == 0x20 && extraBits2 == 0x20) { // A stitch with extrabits 0x20 seems to indicate the current and next stitches are movement only. // Almost always occurs within a block, not the beginning or end. stitchType = Stitch.StitchType.MovementOnly; } else if (extraBits1 == 0x10 && extraBits2 == 0x10) { // A stitch with extrabits 0x10 seems to indicate the current stitch is movement only. // Almost always occurs at the beginning of a block. stitchType = Stitch.StitchType.MovementEndAnchor; } else if (prevStitch != null && (prevStitch.stitchType == Stitch.StitchType.MovementOnly || prevStitch.stitchType == Stitch.StitchType.MovementBeginAnchor)) { stitchType = Stitch.StitchType.MovementEndAnchor; } else { if (firstStitchOfBlock) { // First stitch of block is usually a movement to position the needle in the block firstStitchOfBlock = false; stitchType = Stitch.StitchType.MovementEndAnchor; } else { // Assume everything else is a normal stitch stitchType = Stitch.StitchType.NormalStitch; } } // Add stitch to list prevStitch = new Stitch( new Point(prevX, prevY), new Point(prevX + deltaX, prevY + deltaY), extraBits1, extraBits2, xMoveBits, yMoveBits, stitchType ); tempStitches.Add(prevStitch); // 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; } } } imageWidth = maxX - minX; imageHeight = maxY - minY; translateStart.X = -minX; translateStart.Y = -minY; } } }
private void OpenFile(string filename) { _filename = filename; // The using statements ensure fileIn is closed, no matter how the statement is exited. // 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)) { using (BinaryReader fileIn = new BinaryReader(fileStreamIn)) { string startFileSig = ""; for (int i = 0; i < 4; i++) // 4 bytes { // This needs to be read as a byte, since characters can be multiple bytes depending on encoding startFileSig += (char)fileIn.ReadByte(); } if (startFileSig != "#PES") { // This is not a file that we can read throw new PECFormatException("Missing #PES at beginning of file"); } // PES version string versionString = ""; for (int i = 0; i < 4; i++) // 4 bytes { // This needs to be read as a byte, since characters can be multiple bytes depending on encoding versionString += (char)fileIn.ReadByte(); } if (!UInt16.TryParse(versionString, out pesVersion)) { // This is not a file that we can read throw new PECFormatException("PES version is not the correct format"); } int pecstart = fileIn.ReadInt32(); // Sanity check on PEC start position if (fileIn.BaseStream.Length < (pecstart + 532)) { // This file is probably truncated throw new PECFormatException("File appears to be truncated (PEC section is beyond end of file)"); } // 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++) { colorList.Add(fileIn.ReadByte()); } // 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>(); Stitch prevStitch = null; bool firstStitchOfBlock = true; while (!thisPartIsDone) { 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 start with 2 for the first block and // alternate between 2 and 1 for every other block after that. The only exception // I've noted is the last block which appears to always be 0. curBlock.unknownStartByte = fileIn.ReadByte(); blocks.Add(curBlock); firstStitchOfBlock = true; tempStitches = new List <Stitch>(); } else { int deltaX = 0; int deltaY = 0; int extraBits1 = 0x00; Stitch.MoveBitSize xMoveBits; Stitch.MoveBitSize yMoveBits; 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 0x10 and 0x20. 0x20 occurs // about 4 times as much as 0x10 in the samples I have available. extraBits1 = val1 & 0x70; // This is a 12-bit int. Allows for needle movement // of up to +2047 or -2048. deltaX = get12Bit2sComplement(val1, val2); xMoveBits = Stitch.MoveBitSize.TwelveBits; // 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); xMoveBits = Stitch.MoveBitSize.SevenBits; // 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 & 0x70; // 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); yMoveBits = Stitch.MoveBitSize.TwelveBits; } else { // This is a 7-bit int. Allows for needle movement // of up to +63 or -64. deltaY = get7Bit2sComplement(val1); yMoveBits = Stitch.MoveBitSize.SevenBits; // Finished reading data for this stitch, no more // bytes needed. } Stitch.StitchType stitchType; if (deltaX == 0 && deltaY == 0) { // A stitch with zero movement seems to indicate the current and next stitches are movement only. // Almost always occurs at the end of a block. stitchType = Stitch.StitchType.MovementBeginAnchor; } else if (extraBits1 == 0x20 && extraBits2 == 0x20) { // A stitch with extrabits 0x20 seems to indicate the current and next stitches are movement only. // Almost always occurs within a block, not the beginning or end. stitchType = Stitch.StitchType.MovementOnly; } else if (extraBits1 == 0x10 && extraBits2 == 0x10) { // A stitch with extrabits 0x10 seems to indicate the current stitch is movement only. // Almost always occurs at the beginning of a block. stitchType = Stitch.StitchType.MovementEndAnchor; } else if (prevStitch != null && (prevStitch.stitchType == Stitch.StitchType.MovementOnly || prevStitch.stitchType == Stitch.StitchType.MovementBeginAnchor)) { stitchType = Stitch.StitchType.MovementEndAnchor; } else { if (firstStitchOfBlock) { // First stitch of block is usually a movement to position the needle in the block firstStitchOfBlock = false; stitchType = Stitch.StitchType.MovementEndAnchor; } else { // Assume everything else is a normal stitch stitchType = Stitch.StitchType.NormalStitch; } } // Add stitch to list prevStitch = new Stitch( new Point(prevX, prevY), new Point(prevX + deltaX, prevY + deltaY), extraBits1, extraBits2, xMoveBits, yMoveBits, stitchType ); tempStitches.Add(prevStitch); // 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; } } } imageWidth = maxX - minX; imageHeight = maxY - minY; translateStart.X = -minX; translateStart.Y = -minY; } } }