diff options
| author | Lex Neva <lexelby@users.noreply.github.com> | 2018-05-19 14:41:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-05-19 14:41:50 -0400 |
| commit | 9dadd836e2f09b0216f7b40c782e2b55bcc90dee (patch) | |
| tree | 128b6f13ea682a8e5a033370ab2e13388801f100 /lib/threads/catalog.py | |
| parent | ba7288d8fcd62678bd17d8fab01d0d488d9e21e8 (diff) | |
| parent | 6fe417cd64090f028c0d07b799620eb94637bf33 (diff) | |
Merge pull request #163 from lexelby/lexelby-single-extension
single code entry point
Diffstat (limited to 'lib/threads/catalog.py')
| -rw-r--r-- | lib/threads/catalog.py | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/lib/threads/catalog.py b/lib/threads/catalog.py new file mode 100644 index 00000000..d9981dc6 --- /dev/null +++ b/lib/threads/catalog.py @@ -0,0 +1,97 @@ +import os +from os.path import dirname, realpath +import sys +from glob import glob +from collections import Sequence + +from .palette import ThreadPalette + + +class _ThreadCatalog(Sequence): + """Holds a set of ThreadPalettes.""" + + def __init__(self): + self.palettes = [] + self.load_palettes(self.get_palettes_path()) + + def get_palettes_path(self): + if getattr(sys, 'frozen', None) is not None: + path = os.path.join(sys._MEIPASS, "..") + else: + path = dirname(dirname(dirname(realpath(__file__)))) + + return os.path.join(path, 'palettes') + + def load_palettes(self, path): + for palette_file in glob(os.path.join(path, '*.gpl')): + self.palettes.append(ThreadPalette(palette_file)) + + def palette_names(self): + return list(sorted(palette.name for palette in self)) + + def __getitem__(self, item): + return self.palettes[item] + + def __len__(self): + return len(self.palettes) + + def _num_exact_color_matches(self, palette, threads): + """Number of colors in stitch plan with an exact match in this palette.""" + + return sum(1 for thread in threads if thread in palette) + + def match_and_apply_palette(self, stitch_plan, palette=None): + if palette is None: + palette = self.match_palette(stitch_plan) + else: + palette = self.get_palette_by_name(palette) + + if palette is not None: + self.apply_palette(stitch_plan, palette) + + return palette + + def match_palette(self, stitch_plan): + """Figure out which color palette was used + + Scans the catalog of color palettes and chooses one that seems most + likely to be the one that the user used. A palette will only be + chosen if more tha 80% of the thread colors in the stitch plan are + exact matches for threads in the palette. + """ + + threads = [color_block.color for color_block in stitch_plan] + palettes_and_matches = [(palette, self._num_exact_color_matches(palette, threads)) + for palette in self] + palette, matches = max(palettes_and_matches, key=lambda item: item[1]) + + if matches < 0.8 * len(stitch_plan): + # if less than 80% of the colors are an exact match, + # don't use this palette + return None + else: + return palette + + def apply_palette(self, stitch_plan, palette): + for color_block in stitch_plan: + nearest = palette.nearest_color(color_block.color) + + color_block.color.name = nearest.name + color_block.color.number = nearest.number + color_block.color.manufacturer = nearest.manufacturer + + def get_palette_by_name(self, name): + for palette in self: + if palette.name == name: + return palette + +_catalog = None + +def ThreadCatalog(): + """Singleton _ThreadCatalog factory""" + + global _catalog + if _catalog is None: + _catalog = _ThreadCatalog() + + return _catalog |
