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;
                }
            }
        }
Exemple #2
0
        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;
                }
            }
        }