Skip to content

Commit abb97d7

Browse files
committed
Added some new features and tried to save a little bit of memory.
1 parent a2e0141 commit abb97d7

File tree

10 files changed

+1116
-549
lines changed

10 files changed

+1116
-549
lines changed

CrossStitchProject/CrossStitchProject.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
</ItemGroup>
6262
<ItemGroup>
6363
<Compile Include="CrossStitcher.cs" />
64+
<Compile Include="Helpers\ImageHelper.cs" />
65+
<Compile Include="Helpers\Symbols.cs" />
6466
<Compile Include="Models\Floss.cs" />
6567
<Compile Include="Form1.cs">
6668
<SubType>Form</SubType>
@@ -89,6 +91,7 @@
8991
</Compile>
9092
<EmbeddedResource Include="floss2hex.dat" />
9193
<None Include=".travis.yml" />
94+
<EmbeddedResource Include="symbols.dat" />
9295
<None Include="NotoColorEmoji.ttf">
9396
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
9497
</None>

CrossStitchProject/CrossStitcher.cs

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,64 +10,89 @@ namespace CrossStitchProject
1010
{
1111
public class CrossStitcher
1212
{
13-
private Bitmap Image{ get; }
13+
private Bitmap Picture { get; }
1414
private bool IsColorPattern { get; }
1515
private bool ShouldDitherImage { get; }
1616
private string ProjectName { get; }
17-
private Dictionary<Color,Floss> FlossDict { get; }
1817
public CrossStitcher(Bitmap b, bool isColorPattern, bool shouldDitherImage, string projectName)
1918
{
20-
Image = b;
19+
Picture = b;
2120
IsColorPattern = isColorPattern;
2221
ShouldDitherImage = shouldDitherImage;
2322
ProjectName = projectName;
24-
FlossDict = GenerateFlossDictionary();
2523
}
2624
public void GenerateCrossStitch()
2725
{
28-
var csBitmap = GenerateStitchBitmap();
29-
var htmlWriter = new PatternWriter
30-
(csBitmap,FlossDict,IsColorPattern,ProjectName);
31-
htmlWriter.BuildAndSavePattern();
26+
var flossColors = GetFlossColors();
27+
var csBitmap = GenerateStitchBitmap(flossColors);
28+
var flossDict = GenerateFlossDictionary(csBitmap);
29+
var patternWriter = new PatternWriter
30+
(csBitmap, flossDict, IsColorPattern, ProjectName);
31+
patternWriter.Build();
32+
patternWriter.Save();
3233
}
33-
public Bitmap GenerateStitchBitmap()
34+
public Bitmap GenerateStitchBitmap() => GenerateStitchBitmap(GetFlossColors());
35+
public Bitmap GenerateStitchBitmap(List<Color> validColors)
3436
{
35-
var validColors = FlossDict.Keys.ToList();
3637
var colorMap = new Dictionary<Color, Color>();
37-
for (var y = 0; y < Image.Height; y++)
38+
for (var y = 0; y < Picture.Height; y++)
3839
{
39-
for (var x = 0; x < Image.Width; x++)
40+
for (var x = 0; x < Picture.Width; x++)
4041
{
41-
var origColor = Image.GetPixel(x, y);
42-
if(!colorMap.TryGetValue(origColor,out var closest))
42+
var origColor = Picture.GetPixel(x, y);
43+
if (!colorMap.TryGetValue(origColor, out var closest))
4344
{
4445
closest = ColorMath.GetClosestColor(validColors, origColor);
4546
colorMap.Add(origColor, closest);
4647
}
47-
Image.SetPixel(x,y,closest);
48+
Picture.SetPixel(x, y, closest);
4849
if (!ShouldDitherImage) continue;
49-
ColorMath.FloydSteinberg(Image,origColor,closest,x,y);
50-
50+
ColorMath.FloydSteinberg(Picture, origColor, closest, x, y);
5151
}
5252
}
53-
return Image;
53+
return Picture;
5454
}
55-
private static Dictionary<Color, Floss> GenerateFlossDictionary()
55+
public static List<Color> GetFlossColors()
5656
{
57-
var hex2Floss = new Dictionary<Color, Floss>();
58-
using (var stream = Assembly.GetExecutingAssembly()
57+
var flosses = new List<Color>();
58+
using (var flossStream = Assembly.GetExecutingAssembly()
5959
.GetManifestResourceStream("CrossStitchProject.floss2hex.dat"))
60-
using (var reader = new StreamReader(stream))
60+
using (var flossReader = new StreamReader(flossStream))
6161
{
62-
while (!reader.EndOfStream)
62+
while (!flossReader.EndOfStream)
6363
{
64-
var line = reader.ReadLine();
64+
var line = flossReader.ReadLine();
6565
var splitLine = line.Split(' ');
6666
var flossColor = ColorTranslator.FromHtml(splitLine[1]);
67-
hex2Floss.Add(flossColor, new Floss { DMC = splitLine[0], Symbol = splitLine[2] });
67+
flosses.Add(flossColor);
68+
}
69+
}
70+
return flosses;
71+
}
72+
private static Dictionary<Color,Floss> GenerateFlossDictionary(Bitmap image)
73+
{
74+
var colorsNeeded = ImageHelper.GetColors(image);
75+
var dict = new Dictionary<Color, Floss>();
76+
var symbolEnumerator = Symbols.GetSymbols().GetEnumerator();
77+
using (var flossStream = Assembly.GetExecutingAssembly()
78+
.GetManifestResourceStream("CrossStitchProject.floss2hex.dat"))
79+
using (var flossReader = new StreamReader(flossStream))
80+
{
81+
while (!flossReader.EndOfStream)
82+
{
83+
var line = flossReader.ReadLine();
84+
var splitLine = line.Split(' ');
85+
var flossColor = ColorTranslator.FromHtml(splitLine[1]);
86+
if (!colorsNeeded.Contains(flossColor)) { continue; }
87+
dict.Add(flossColor, new Floss
88+
{
89+
DMC = int.Parse(splitLine[0]),
90+
Symbol = symbolEnumerator.Current
91+
});
92+
symbolEnumerator.MoveNext();
6893
}
6994
}
70-
return hex2Floss;
95+
return dict;
7196
}
7297
}
7398
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace CrossStitchProject.Helpers
9+
{
10+
public class ImageHelper
11+
{
12+
public static HashSet<Color> GetColors(Bitmap b)
13+
{
14+
var colorSet = new HashSet<Color>();
15+
for (var y = 0; y < b.Height; y++)
16+
for (var x = 0; x < b.Width; x++)
17+
colorSet.Add(b.GetPixel(x, y));
18+
return colorSet;
19+
}
20+
}
21+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace CrossStitchProject.Helpers
10+
{
11+
public class Symbols
12+
{
13+
public static IEnumerable<string> GetSymbols()
14+
{
15+
using (var symbolStream = Assembly.GetExecutingAssembly()
16+
.GetManifestResourceStream("CrossStitchProject.symbols.dat"))
17+
using (var symbolReader = new StreamReader(symbolStream))
18+
{
19+
while(!symbolReader.EndOfStream)
20+
{
21+
yield return symbolReader.ReadLine();
22+
}
23+
}
24+
}
25+
}
26+
}

CrossStitchProject/Models/Floss.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{
33
public class Floss
44
{
5-
public string DMC { get; set; }
5+
public int DMC { get; set; }
66
public string Symbol { get; set; }
77
}
88
}

CrossStitchProject/Models/PatternChunk.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ public class PatternChunk
1212
public bool IsColorPattern { get; set; }
1313
public Bitmap Chunk { get; set; }
1414
public Dictionary<Color, Floss> ColorToFlossDict { get; set; }
15+
public int StartX { get; set; }
16+
public int StartY { get; set; }
1517
}
1618
}

CrossStitchProject/PatternWriter.cs

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,92 +15,98 @@ namespace CrossStitchProject
1515
{
1616
public class PatternWriter
1717
{
18-
private readonly List<Bitmap> _imageChunks = new List<Bitmap>();
18+
public List<List<Bitmap>> _imageChunks = new List<List<Bitmap>>();
19+
public List<string> PatternChunks;
20+
public string PatternLegend;
1921
private readonly Dictionary<Color, Floss> _color2Floss;
20-
private readonly bool _isColored;
22+
private readonly bool _isColorPattern;
2123
private const decimal DefaultChunkWidth = 50.0M;
2224
private const decimal DefaultChunkHeight = 60.0M;
2325
private static string _outputPath;
24-
public List<string> PatternChunks;
25-
public string PatternLegend;
26+
const string CrossStitchFolderName = "Cross Stitch Patterns";
2627

2728
public PatternWriter(Bitmap b, Dictionary<Color, Floss> c2F, bool colored, string outDir)
2829
{
2930
PatternChunks = new List<string>();
3031
ChunkifyImage(b);
3132

32-
_isColored = colored;
33+
_isColorPattern = colored;
3334
_color2Floss = c2F;
3435

3536
var pictureFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
37+
var crossStitchFolder = Path.Combine(pictureFolder, CrossStitchFolderName);
3638
if (string.IsNullOrEmpty(outDir)) { outDir = "MyCrossStitchPattern"; }
37-
_outputPath = Path.Combine(pictureFolder, outDir);
39+
_outputPath = Path.Combine(crossStitchFolder, outDir);
3840

41+
if (!Directory.Exists(crossStitchFolder)) { Directory.CreateDirectory(crossStitchFolder); }
3942
if (!Directory.Exists(_outputPath)) { Directory.CreateDirectory(_outputPath); }
4043
}
41-
public void BuildAndSavePattern()
44+
public void Build()
4245
{
43-
var task = Task.Factory.StartNew(() => GetDistinctFlossesInImage());
4446
BuildCrossStitchPattern();
45-
GenerateHtmlLegend(task.Result);
47+
BuildLegend();
48+
}
49+
public void Save()
50+
{
4651
for (var i = 0; i < PatternChunks.Count; i++)
4752
{
48-
Save(PatternChunks[i],$"chunk{i+1}.html");
53+
Save(PatternChunks[i], $"chunk{i + 1}.html");
4954
}
50-
Save(PatternLegend,"legend.html");
55+
Save(PatternLegend, "legend.html");
5156
}
5257

5358
private void ChunkifyImage(Bitmap b)
5459
{
5560
var numHorizontalChunks = (int)Math.Ceiling(b.Width / DefaultChunkWidth);
5661
var numVerticalChunks = (int)Math.Ceiling(b.Height / DefaultChunkHeight);
57-
for (var y = 0; y < numVerticalChunks; y++)
62+
for (var y = 0; y < numVerticalChunks; y++)
63+
{
64+
_imageChunks.Add(new List<Bitmap>());
5865
for (var x = 0; x < numHorizontalChunks; x++)
5966
{
6067
var widthLeft = b.Width - (x + 1) * DefaultChunkWidth;
6168
var heightLeft = b.Height - (y + 1) * DefaultChunkHeight;
62-
var curChunkWidth = (int)(widthLeft < 0 ? widthLeft + DefaultChunkWidth: DefaultChunkWidth);
63-
var curChunkHeight = (int)(heightLeft < 0 ? heightLeft + DefaultChunkHeight: DefaultChunkHeight);
69+
var curChunkWidth = (int)(widthLeft < 0 ? widthLeft + DefaultChunkWidth : DefaultChunkWidth);
70+
var curChunkHeight = (int)(heightLeft < 0 ? heightLeft + DefaultChunkHeight : DefaultChunkHeight);
6471
var chunk = b.Clone(
65-
new Rectangle(x * (int) DefaultChunkWidth, y * (int) DefaultChunkHeight, curChunkWidth,
72+
new Rectangle(x * (int)DefaultChunkWidth, y * (int)DefaultChunkHeight, curChunkWidth,
6673
curChunkHeight), PixelFormat.Format32bppArgb);
67-
_imageChunks.Add(chunk);
74+
_imageChunks[y].Add(chunk);
6875
}
76+
}
6977
}
7078
private void Save(string outString, string filename)
7179
{
7280
File.WriteAllText(Path.Combine(_outputPath, filename), outString);
7381
Process.Start(_outputPath);
7482
}
7583

76-
private void GenerateHtmlLegend(HashSet<Floss> flosses)
84+
private void BuildLegend()
7785
{
78-
var model = flosses.ToList();
86+
var model = _color2Floss.Values.OrderBy(x => x.DMC).ToList();
7987
var template = File.ReadAllText("Templates/legend_razor.html");
80-
var result = Engine.Razor.RunCompile(template,"legendKey", null, model);
88+
var result = Engine.Razor.RunCompile(template, "legendKey", null, model);
8189
PatternLegend = result;
8290
}
8391
private void BuildCrossStitchPattern()
8492
{
85-
foreach (var chunk in _imageChunks)
86-
{
87-
var template = File.ReadAllText("Templates/pattern_razor.html");
88-
var model = new PatternChunk { Chunk = chunk, ColorToFlossDict = _color2Floss, IsColorPattern = _isColored };
89-
//Engine.Razor = RazorEngineService.Create(new TemplateServiceConfiguration { Debug = true });
90-
var result = Engine.Razor.RunCompile(template,"patternKey", null, model);
91-
PatternChunks.Add(result);
92-
}
93-
}
94-
private HashSet<Floss> GetDistinctFlossesInImage()
95-
{
96-
var flossesUsed = new HashSet<Floss>();
97-
foreach (var chunk in _imageChunks)
98-
for (var y = 0; y < chunk.Height; y++)
99-
for (var x = 0; x < chunk.Width; x++)
93+
for (var y = 0; y < _imageChunks.Count; y++)
94+
for (var x = 0; x < _imageChunks[y].Count; x++)
95+
{
96+
var startY = y * (int)DefaultChunkHeight;
97+
var startX = x * (int)DefaultChunkWidth;
98+
var template = File.ReadAllText("Templates/pattern_razor.html");
99+
var model = new PatternChunk
100100
{
101-
flossesUsed.Add(_color2Floss[chunk.GetPixel(x, y)]);
102-
}
103-
return flossesUsed;
101+
Chunk = _imageChunks[y][x],
102+
ColorToFlossDict = _color2Floss,
103+
IsColorPattern = _isColorPattern,
104+
StartX = startX,
105+
StartY = startY
106+
};
107+
var result = Engine.Razor.RunCompile(template, "patternKey", null, model);
108+
PatternChunks.Add(result);
109+
}
104110
}
105111
}
106112
}

0 commit comments

Comments
 (0)