Example #1
0
        /// <summary>
        /// Converts the users image to the size they specify
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void WidthValue_ValueChanged(object sender, EventArgs e)
        {
            if (!loading)
            {
                converted = false;
                //if no image is present, don't try to resize
                if (UserImageBox.Image == null)
                {
                    return;
                }

                //maxSize needs to be set to the new resized with value
                //if not, upon second conversion attempt it will still be the original width of 100
                maxSize = Convert.ToInt32(Math.Round(WidthValue.Value, 0));
                //if image is present, resize it to specified width.
                resized = ConvertImg.resizeImage(toConvert,
                                                 toConvert.Width,
                                                 toConvert.Height,
                                                 maxSize);

                //store resized image, ready to be colour matched and converted to DMC olny colours
                numericUpDown1.Value = resized.Height;

                //redraw the image
                ResetProgressBar();
                Invalidate();
            }
        }
Example #2
0
        //Load everything from save file
        public void LoadSession()
        {
            ApplicationData loadData = new ApplicationData();

            string json;

            try
            {
                if (loadLast)
                {
                    json = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + $"/LastSession.json");
                }
                else
                {
                    openFileDialog1.Filter           = "Saved Conversions (*.json) | *.json";
                    openFileDialog1.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory + "Saves";
                    openFileDialog1.ShowDialog();
                    json = File.ReadAllText(openFileDialog1.FileName);
                }

                loadData = JsonConvert.DeserializeObject <ApplicationData>(json);

                loading            = true;
                converted          = true;
                imageLoaded        = true;
                sourceFile         = loadData.sourceFile;
                fileName           = loadData.fileName;
                dmcDataStore       = loadData.dmcDataStrore;
                rgbArray           = loadData.rgbArray;
                rgbArrayToDrawFrom = loadData.rgbArrayToDrawFrom;
                selectedDMCValues  = loadData.selectedDMCValues;
                maxSize            = loadData.maxSize;
                resized            = ConvertImg.resizeImage(Image.FromFile(loadData.sourceFile),
                                                            loadData.imgWidth,
                                                            loadData.imgHeight,
                                                            maxSize);
                toConvert            = resized;
                UserImageBox.Image   = resized;
                tickedCount          = loadData.tickedCount;
                numericUpDown2.Value = loadData.threadAmount;
                threadAmount         = loadData.threadAmount;
                numericUpDown3.Value = loadData.imageGridSize;
                numericUpDown1.Value = loadData.imgHeight;
                WidthValue.Value     = loadData.imgWidth;
                imgWidth             = loadData.imgWidth;
                imgHeight            = loadData.imgHeight;
                markedPositions      = loadData.markedPositions;
                loading = false;

                progressBar.Value    = 100;
                ProgressBarText.Text = "Conversion Complete";
            }
            catch (Exception)
            {
                return;
            }

            Invalidate();
        }
Example #3
0
        public void LoadImageButon_Click(object sender, EventArgs e)
        {
            #region Load Image
            if (!loading)
            {
                //sets current progress bar to 0
                progressBar.Value = 0;

                //only allows user to pick and load image files
                openFileDialog1.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";

                //assigns the picked file a variable name 'imageToConvert'
                DialogResult imageToConvert = openFileDialog1.ShowDialog();

                //get path of selected file, and change file to png
                sourceFile = openFileDialog1.FileName;
                string targetFile = Path.ChangeExtension(sourceFile, "png");

                fileName = sourceFile.Split('\\').Last();
                fileName = fileName.Substring(0, fileName.Length - 4);
            }

            //load image png and assign it to an Image variable
            //this is here to catch the event a user opens the load dialogue and presses the cancel button, without loading an image.
            try
            {
                image       = Image.FromFile(sourceFile);
                imageLoaded = true;
            }
            catch (Exception)
            {
                return;
            }

            //load image to image display box, set it to fill the box
            if (image.Width > image.Height)
            {
                UserImageBox.Image = ConvertImg.resizeImage(image,
                                                            image.Width,
                                                            image.Height,
                                                            UserImageBox.Width);
            }
            else
            {
                float ratio    = (float)image.Width / (float)image.Height;
                int   newWidth = (int)(ratio * UserImageBox.Height);

                UserImageBox.Image = ConvertImg.resizeImage(image,
                                                            image.Width,
                                                            image.Height,
                                                            newWidth);
            }

            toConvert = image;

            //resize image to 100 stitches
            resized = ConvertImg.resizeImage(toConvert,
                                             toConvert.Width,
                                             toConvert.Height,
                                             maxSize);
            WidthValue.Value = 100;
            #endregion
        }
Example #4
0
        //run the conversion in an async task to free up the ui thread
        //prevents the program looking like it has frozen
        //also prevents "not responding" when trying to use the program while converting
        private async Task RunConversion()
        {
            //WARNING
            //if amount of selectable dmc threads changes in the future, this will not display the correct number present in the palette
            //currently starts at 454 as every checkbox is reset to false upon starting a new conversion.
            //so when count is incremented, it was starting from -454, not 0;
            int count = 454;
            //WARNING

            var progress = new Progress <int>(value =>
            {
                base.Invoke((Action) delegate
                {
                    progressBar.Value = ConvertImg.Clamp(0, 100, value);
                });
            });

            var unCheckItem = new Progress <int>(index =>
            {
                base.Invoke((Action) delegate
                {
                    dmcPaletteBox.SetItemChecked(index, false);
                    count--;
                });
            });

            //should pass all the values to be checked at the end of the conversion, and set them in one call
            var checkItem = new Progress <int>(index =>
            {
                base.Invoke((Action) delegate
                {
                    dmcPaletteBox.SetItemChecked(index, true);
                    count++;
                    paletteCount.Text = "Palette Count\n" + count.ToString() + " / " + dmcPaletteBox.Items.Count.ToString();
                });
            });

            var loadingText = new Progress <string>(str =>
            {
                base.Invoke((Action) delegate
                {
                    ProgressBarText.Text = str;
                });
            });

            await Task.Run(() =>
            {
                //call the process image method the convert our image to DMC values and display the values on a grid
                //store the returned dmc pixel array and rgbArray to recall them if user accidentally marks the wrong grid cell
                Console.WriteLine($"drawing with height and width of x ={resized.Width}, y={resized.Height}");
                Tuple <string[, ], Color[, ]> tupleReturn = ConvertImg.processImage(loadingText, progress, unCheckItem, checkItem, threadAmount, resized, selectedDMCValues, progressBar, ProgressBarText, algo, allDMCValues, dmcPaletteBox, dither, ditherFactor, commonColourSensitivity.Value);
                dmcDataStore       = tupleReturn.Item1;
                rgbArray           = tupleReturn.Item2;
                rgbArrayToDrawFrom = tupleReturn.Item2;
                Console.WriteLine($"array from convert image func x ={rgbArrayToDrawFrom.GetLength(1)}, y={rgbArrayToDrawFrom.GetLength(0)}");

                //update palette counter, just in case user generated threads and didnt pick any
                tickedCount = dmcPaletteBox.CheckedItems.Count;

                //tell program that a conversion has just taken place
                //this is here to prevent drawing the grid colors, before the grid colours have been established
                //DrawImage function checks for this
                converted = true;

                //store selected values, this will be used if creating a pdf
                selectedDMCValues = new List <String>(dmcPaletteBox.CheckedItems.Cast <String>());
                Invalidate();
            });
        }
        public void Create(Image image, string[,] dmcGrid, List <string> selectedDMCValues, string fileName)
        {
            Dictionary <string, string> dmcToShortText = new Dictionary <string, string>();
            Dictionary <string, Color>  dmcValues      = new Dictionary <string, Color>();

            PdfDocument document = new PdfDocument();

            //Create multiple pages to fit an entire conversion prjoect on
            //first need to break up the image, using the DMCgridarray's width and height.
            //then calculate how many pages it needs by breaking it up into chunks of a set width and height
            //create a page for each chunk using a set of starting co-ordinates that reference the DMCgrid

            //starting by assigning each dmc value an id
            //assemble the dictionary of dmc values and assign them a short text code

            #region Assign DMC values a short text code

            //sets how wide the grid is on the page
            int gridsize = 18;

            //stores what letters are accessed when creating the dict of dmc codes
            int xyzID = 0;
            int numID = 0;

            //string which is indexed for the creation of short dmc codes
            string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            //itterate over each grid, if the dmc value is not present in the dict, add it as a key
            //and make its value a letter from the alphabet and a number. starting at A0.
            //increment the latter, so the next time a new value is stored it is the next letter of alphabet
            //if alphabet gets to Z, increase the number by 1 and start from A again
            for (int i = 0; i < dmcGrid.GetLength(0); i++)
            {
                for (int j = 0; j < dmcGrid.GetLength(1); j++)
                {
                    if (!dmcToShortText.ContainsKey(dmcGrid[i, j]))
                    {
                        dmcToShortText.Add(dmcGrid[i, j], $"{alphabet[xyzID]}{numID}");

                        if (alphabet[xyzID] == 'Z')
                        {
                            xyzID = 0;
                            numID++;
                        }
                        else
                        {
                            xyzID++;
                        }
                    }
                }
            }
            #endregion

            #region This is where the image is broken into chunks

            //store the width and height of the grid
            int gridCellNumW = dmcGrid.GetLength(0);
            int gridCellNumH = dmcGrid.GetLength(1);

            //Set how many grid cells you want on each page(width and height)
            int cellNumWPerPage = 20;
            int cellNumHPerPage = 20;

            //create a list of each top left coordinate in each chunk
            List <int[]> chunkTopLeft = new List <int[]>();

            for (int i = 0; i < gridCellNumW / cellNumWPerPage; i++)
            {
                for (int j = 0; j < gridCellNumH / cellNumHPerPage; j++)
                {
                    chunkTopLeft.Add(new int[] { i *cellNumWPerPage, j *cellNumHPerPage });
                }
            }
            #endregion

            #region Create dmcValue dictionaryto hold dmc id and colour data
            foreach (var item in selectedDMCValues)
            {
                string[] dmcString = item.Split('\t');

                Color col = Color.FromArgb(Convert.ToInt32(dmcString[2]),
                                           Convert.ToInt32(dmcString[3]),
                                           Convert.ToInt32(dmcString[4]));

                dmcValues.Add(dmcString[0], col);
            }
            #endregion

            #region This is where the drawing happens
            //This needs to be done for each page
            //Starting with the first, as it is different every time.
            //After page one, the page drawing can be itterated through, as they all follow the same procedure

            #region Page One
            //Create intro page, including image of conversion and a map showing the area each page covers

            //Add a new page (page1)
            document.AddPage();

            //first page graphics, and brushes/fonts
            XGraphics       gfx     = XGraphics.FromPdfPage(document.Pages[0]);
            XPdfFontOptions options = new XPdfFontOptions(PdfFontEncoding.Unicode);

            //create image var (img) from users image, that will be shown on the first page of the pdf
            MemoryStream strm = new MemoryStream();

            //resize image
            //if image is taller than is wide, resize it based on its height
            if (image.Width > image.Height)
            {
                image = ConvertImg.resizeImage(image, image.Width, image.Height, 765);
            }
            else
            {
                image = ConvertImg.resizeImage(image, image.Width, image.Height, 765 / 2);
            }

            image.Save(strm, System.Drawing.Imaging.ImageFormat.Png);

            XImage img = XImage.FromStream(strm);

            //create fonts for text, and brushes for the colours of text and grid
            XFont  font     = new XFont("Consolas", 10, XFontStyle.Regular, options);
            XBrush brush    = XBrushes.Black;
            XPen   thinLine = new XPen(XColor.FromArgb(Color.Black.ToArgb()), 1);
            XPen   wideLine = new XPen(XColor.FromArgb(Color.Black.ToArgb()), 3);

            //draw the image (since gfx is referencing page 1, this is where it is drawn)
            int imgOffX = 10;
            int imgOffY = 10;
            gfx.DrawImage(img, imgOffX, imgOffY);

            //draw the text codes for each dmc value that is used in the project
            //convert dict of dmc text codes to a string for drawing
            int startX    = imgOffX;
            int lineSpace = 10;
            int startY    = imgOffY + img.PixelHeight;
            int count     = 1;

            foreach (var item in dmcToShortText.Keys)
            {
                string keyString = $"{dmcToShortText[item]} = {item}";

                gfx.DrawString(keyString, font, brush, startX, (count * lineSpace) + startY - 50);

                //draw a square next to each string showing its thread colour (needs converted colour data)
                XPen dmcCol = new XPen(XColor.FromArgb(dmcValues[item].ToArgb()), 6);

                gfx.DrawRectangle(dmcCol, new XRect(new XPoint(startX + 60, (count * lineSpace) + startY - 56), new XSize(5, 5)));

                count++;
            }
            #endregion End of page one region

            #region Pages with chart
            //This is where the grid will be broken down to make it readable across multiple pages.

            //These 2 variables determine how many cells there are (width and height)
            //currently it is the maximum, but i should be able to set it to say 30 and 30,
            //and have the page only display 30 across and 30 down
            int h = 30;
            int w = 30;

            //first, break down the grid into h by w chunks.
            //store chunk start positions in a list
            List <int[]> chunks = new List <int[]>();

            //calculate how many chunks wide and high
            int chunkH = (int)Math.Ceiling(dmcGrid.GetLength(0) / (float)h);
            int chunkW = (int)Math.Ceiling(dmcGrid.GetLength(1) / (float)w);

            for (int i = 0; i < chunkH; i++)
            {
                for (int j = 0; j < chunkW; j++)
                {
                    chunks.Add(new int[] { j *w, i *h });

                    Console.WriteLine($"new chunk at {j * w},{i * h}");
                }
            }

            //create a page for every chunk
            for (int a = 0; a < chunks.Count; a++)
            {
                document.AddPage();

                gfx = XGraphics.FromPdfPage(document.Pages[a + 1]); //a+1 because first page already exists

                int textwOffset = 20;
                int texthOffset = 20;

                int linewOffset = textwOffset + -4;
                int linehOffset = texthOffset + -12;

                //drawtext in a grid that shows short text code of each dmc pixel
                //start at chunk location and go up to chunk location +h,w
                int y = 0;
                int x = 0;
                for (int i = chunks[a][1]; i < chunks[a][1] + h; i++)
                {
                    for (int j = chunks[a][0]; j < chunks[a][0] + w; j++)
                    {
                        if (i < dmcGrid.GetLength(0) && j < dmcGrid.GetLength(1))
                        {
                            gfx.DrawString(dmcToShortText[dmcGrid[i, j]], font, brush, (x * gridsize) + textwOffset, (y * gridsize) + texthOffset);
                        }

                        x++;
                    }

                    y++;
                    x = 0;
                }

                //draw a line grid over the text
                //horizontal lines, with 10th line being thicker
                y = 0;
                x = 0;
                for (int i = chunks[a][1]; i < chunks[a][1] + h + 1; i++)
                {
                    if (i % 10 == 0)
                    {
                        if (i <= dmcGrid.GetLength(0))
                        {
                            gfx.DrawLine(wideLine, new XPoint(0 + linewOffset, (y * gridsize) + linehOffset), new XPoint((w * gridsize) + linewOffset, (y * gridsize) + linehOffset));
                        }
                    }
                    else
                    {
                        if (i <= dmcGrid.GetLength(0))
                        {
                            gfx.DrawLine(thinLine, new XPoint(0 + linewOffset, (y * gridsize) + linehOffset), new XPoint((w * gridsize) + linewOffset, (y * gridsize) + linehOffset));
                        }
                    }
                    y++;
                }

                //vertical lines, with 10th line being thicker
                for (int i = chunks[a][0]; i < chunks[a][0] + w + 1; i++)
                {
                    if (i % 10 == 0)
                    {
                        if (i <= dmcGrid.GetLength(1))
                        {
                            gfx.DrawLine(wideLine, new XPoint((x * gridsize) + linewOffset, linehOffset), new XPoint((x * gridsize) + linewOffset, (h * gridsize) + linehOffset));
                        }
                    }
                    else
                    {
                        if (i <= dmcGrid.GetLength(1))
                        {
                            gfx.DrawLine(thinLine, new XPoint((x * gridsize) + linewOffset, linehOffset), new XPoint((x * gridsize) + linewOffset, (h * gridsize) + linehOffset));
                        }
                    }

                    x++;
                }
            }
            #endregion End of chart region
            #endregion End of drawing region

            string pdf = AppDomain.CurrentDomain.BaseDirectory + $"/PDF_Charts/{fileName}.pdf";

            //save the pdf
            document.Save(pdf);

            //opens the pdf for the user
            Process.Start(pdf);
        }