示例#1
0
        public static HybridMap2 LoadFromDisk(string dir, IFontProvider f, IPixelFormatProvider pf)
        {
            HybridMap2 ret = new HybridMap2();

            Log.WriteLine("Loading charinfo...");
            string sci = System.IO.File.ReadAllText(System.IO.Path.Combine(dir, "CharInfo.json"));

            ret.CharInfo = Newtonsoft.Json.JsonConvert.DeserializeObject <CharInfo[]>(sci);

            Log.WriteLine("Loading DistinctMappedChars...");
            string sdmc = System.IO.File.ReadAllText(System.IO.Path.Combine(dir, "DistinctMappedChars.json"));

            ret.DistinctMappedChars = Newtonsoft.Json.JsonConvert.DeserializeObject <CharInfo[]>(sdmc);

            ret.FontProvider        = f;
            ret.PixelFormatProvider = pf;

            return(ret);
        }
示例#2
0
        public unsafe HybridMap2(IFontProvider fontProvider, IPixelFormatProvider pixelFormatProvider,
                                 string fullMapPath, string refMapPath, string refFontPath, int coreCount, int partitionsPerDim, int?partitionDepth)
        {
            if (coreCount < 1)
            {
                coreCount = System.Environment.ProcessorCount - coreCount;
            }

            this.FontProvider        = fontProvider;
            this.PixelFormatProvider = pixelFormatProvider;
            this.FontProvider.Init(this.PixelFormatProvider.DiscreteNormalizedValues.Length);

            Log.WriteLine("  DiscreteNormalizedValues:");
            for (int i = 0; i < PixelFormatProvider.DiscreteNormalizedValues.Length; ++i)
            {
                if (i > 14)
                {
                    Log.WriteLine("    ...");
                    break;
                }
                Log.WriteLine("    {0}: {1,10:0.00}", i, PixelFormatProvider.DiscreteNormalizedValues[i]);
            }

            Log.WriteLine("Number of source chars (1d): " + this.FontProvider.CharCount.ToString("N0"));
            Log.WriteLine("Chosen values per tile: " + pixelFormatProvider.DiscreteNormalizedValues.Length);
            Log.WriteLine("Dimensions: " + PixelFormatProvider.DimensionCount);
            Log.WriteLine("Resulting map will have this many entries: " + pixelFormatProvider.MapEntryCount.ToString("N0"));
            long mapdimpix = (long)Math.Sqrt(pixelFormatProvider.MapEntryCount);

            Log.WriteLine("Resulting map will be about: [" + mapdimpix.ToString("N0") + ", " + mapdimpix.ToString("N0") + "]");

            // fill in char source info (actual tile values)
            Log.EnterTask("Analyze incoming font");
            this.CharInfo = new CharInfo[FontProvider.CharCount];// new List<CharInfo>();

            for (int ichar = 0; ichar < FontProvider.CharCount; ++ichar)
            {
                var ci = new CharInfo(PixelFormatProvider.DimensionCount)
                {
                    srcIndex = ichar,
#if DEBUG
                    //fontImageCellPos = FontProvider.GetCharPosInChars(ichar),
                    //fontImagePixelPos = FontProvider.GetCharOriginInPixels(ichar),
#endif
                };
                pixelFormatProvider.PopulateCharColorData(ci, fontProvider);
                this.CharInfo[ichar] = ci;
            }

            Log.WriteLine("Number of source chars: " + this.CharInfo.Length);

            PartitionManager pm = new PartitionManager(partitionsPerDim, partitionDepth.GetValueOrDefault(PixelFormatProvider.DimensionCount + 1), PixelFormatProvider.DiscreteNormalizedValues);

            // create list of all mapkeys
            Log.EnterTask("Generating {0:N0} map key indices", pixelFormatProvider.MapEntryCount);
            this.Keys = Utils.Permutate(PixelFormatProvider.DimensionCount, pixelFormatProvider.DiscreteNormalizedValues); // returns sorted.
            // populate the denormalized values
            for (int i = 0; i < this.Keys.Length; ++i)
            {
                this.Keys[i].DenormalizedValues = this.PixelFormatProvider.Denormalize(this.Keys[i].NormalizedValues);
            }

            Log.EndTask();

            Log.WriteLine("Key count: " + this.Keys.Length);

            foreach (var ci in this.CharInfo)
            {
                pm.AddItem(ci);
            }

            Log.EndTask();
            Log.EnterTask("Calculate all mappings");

            // - generate a list of mappings and their distances
            ulong theoreticalMappings = (ulong)this.CharInfo.Length * (ulong)pixelFormatProvider.MapEntryCount;

            Log.WriteLine("  Theoretical mapping count: " + theoreticalMappings.ToString("N0"));

            List <Task> comparisonBatches = new List <Task>();
            var         Map = new Mapping[Keys.Length];// indices need to be synchronized with Keys.

            for (int icore = 0; icore < coreCount; ++icore)
            {
                // create a task to process a segment of keys
                ulong keyBegin = (ulong)icore;
                keyBegin *= (ulong)Keys.Length;
                keyBegin /= (ulong)coreCount;

                ulong keyEnd = (ulong)icore + 1;
                keyEnd *= (ulong)Keys.Length;
                keyEnd /= (ulong)coreCount;

                int  coreID     = icore;
                bool isLastCore = (icore == coreCount - 1);

                comparisonBatches.Add(Task.Run(() =>
                {
                    PopulateMap(keyBegin, keyEnd, coreID, isLastCore, pm, Map);
                }));
            }
            Task.WaitAll(comparisonBatches.ToArray());
            Log.EndTask();

            // todo: a histogram would be more informative than this crap.
            int      numCharsUsed     = 0;
            int      numCharsUsedOnce = 0;
            CharInfo mostUsedChar     = null;
            int      numRepetitions   = 0;

            foreach (var ci in this.CharInfo)
            {
                if (mostUsedChar == null || mostUsedChar.usages < ci.usages)
                {
                    mostUsedChar = ci;
                }
                if (ci.usages > 0)
                {
                    numCharsUsed++;
                }
                if (ci.usages == 1)
                {
                    numCharsUsedOnce++;
                }
                if (ci.usages > 1)
                {
                    numRepetitions += ci.usages - 1;
                }
            }

            Log.WriteLine("Process currently using {0:0.00} mb of memory)", Utils.BytesToMb(Utils.UsedMemoryBytes));

#if false
            OutputFullMap(fullMapPath, Map);
#endif

            DistinctMappedChars = Map.DistinctBy(o => o.icharInfo).Select(o => this.CharInfo[o.icharInfo]).ToArray();
            for (int ichar = 0; ichar < DistinctMappedChars.Length; ++ichar)
            {
                CharInfo ci = DistinctMappedChars[ichar];
                Debug.Assert(ci != null);
                ci.refFontIndex = ichar;
            }

            OutputRefMapAndFont(refMapPath, refFontPath, Map);


            // save data structures
            string jsonDistinctMappedChars = Newtonsoft.Json.JsonConvert.SerializeObject(DistinctMappedChars, Newtonsoft.Json.Formatting.Indented);
            System.IO.File.WriteAllText(System.IO.Path.Combine(refMapPath, "..\\DistinctMappedChars.json"), jsonDistinctMappedChars);

            //string jsonKeys = Newtonsoft.Json.JsonConvert.SerializeObject(Keys, Newtonsoft.Json.Formatting.Indented);
            //System.IO.File.WriteAllText(System.IO.Path.Combine(refMapPath, "..\\Keys.json"), jsonKeys);

            string jsonCharInfo = Newtonsoft.Json.JsonConvert.SerializeObject(CharInfo, Newtonsoft.Json.Formatting.Indented);
            System.IO.File.WriteAllText(System.IO.Path.Combine(refMapPath, "..\\CharInfo.json"), jsonCharInfo);

            //string jsonMap = Newtonsoft.Json.JsonConvert.SerializeObject(Map, Newtonsoft.Json.Formatting.Indented);
            //System.IO.File.WriteAllText(System.IO.Path.Combine(refMapPath, "..\\Map.json"), jsonMap);

            Log.WriteLine("Post-map stats:");
            Log.WriteLine("  Used char count: " + numCharsUsed);
            Log.WriteLine("  Number of unused char: " + (this.CharInfo.Length - numCharsUsed));
            Log.WriteLine("  Number of chars used exactly once: " + numCharsUsedOnce);
            Log.WriteLine("  Most-used char: " + mostUsedChar + " (" + mostUsedChar.usages + ") usages");
            Log.WriteLine("  Number of total char repetitions: " + numRepetitions);
        }
示例#3
0
        static void Main2(string[] args)
        {
#if !DEBUG
            try
            {
#else
            {
#endif

                Log.WriteLine("----------------------------------------");

                //PartitionManager partitionManager = null;// = new PartitionManager(1, 1, discreteValues);
                int partitionsPerDimension             = 1;
                int?partitionDepth                     = null;
                IPixelFormatProvider pixelFormat       = null;
                IFontProvider        fontProvider      = null;
                string        outputDir                = null;
                List <string> processImages            = new List <string>();
                int           coresToUtilize           = System.Environment.ProcessorCount;
                List <System.Drawing.Color> testColors = new List <System.Drawing.Color>();

                args.ProcessArg(new string[] { "-help", "-?", "-h" }, s =>
                {
                    var assem = System.Reflection.Assembly.GetExecutingAssembly();// typeof(PartitionManager).Assembly;
                    var ns    = assem.EntryPoint.DeclaringType.Namespace;
                    using (Stream stream = assem.GetManifestResourceStream(ns + ".cmdhelp.txt"))
                    {
                        using (var reader = new StreamReader(stream))
                        {
                            while (!reader.EndOfStream)
                            {
                                string ln = reader.ReadLine();
                                Log.WriteLine(ln);
                            }
                        }
                    }
                });

                bool didluts = false;
                args.ProcessArg("-createlut", s =>
                {
                    var colorSpace = Utils.ParseRequiredLCCColorSpaceArgs(args, true);
                    string outfile = null;
                    args.ProcessArg("-o", s2 => { outfile = s2; });
                    List <System.Drawing.Color> palette = new List <System.Drawing.Color>();
                    string paletteName = null;
                    args.ProcessArg("-palette", s2 =>
                    {
                        paletteName = s2;
                        palette.AddRange(Utils.GetNamedPalette(s2));
                    });
                    int levels = 32;
                    args.ProcessArg("-levels", s2 => { levels = int.Parse(s2); });
                    bool useChroma = false;
                    args.ProcessArg("-lcc", s2 => { useChroma = true; });
                    bool neutral = false;
                    args.ProcessArg("-neutral", s2 => { neutral = true; });
                    CreateLUT(paletteName, palette.ToArray(), outfile, colorSpace, levels, useChroma, neutral);
                    didluts = true;
                    return;
                });
                if (didluts)
                {
                    return;
                }

                args.ProcessArg("-listpalettes", s =>
                {
                    Log.WriteLine("Listing palettes:");
                    foreach (var p in typeof(Palettes).GetProperties())
                    {
                        Log.WriteLine("  {0}", p.Name);
                    }
                });

                args.ProcessArg("-viewpalette", s =>
                {
                    Log.WriteLine("Listing palette entries for palette:");
                    Log.WriteLine("{0}", s);
                    var p = Utils.GetNamedPalette(s);
                    Log.WriteLine("{0} entries", p.Length);
                    for (int i = 0; i < p.Length; ++i)
                    {
                        var c = p[i];
                        Log.WriteLine("{0:000}: {1} {2}",
                                      i,
                                      ColorTranslator.ToHtml(c),
                                      ColorMapper.GetNearestName(c));
                    }
                });

                args.ProcessArg("-argsfile", s =>
                {
                    Log.WriteLine("Reading args from file: {0}" + s);
                    var lines = System.IO.File.ReadAllLines(s)
                                .Select(l => l.Split('#')[0])               // remove comments
                                .Where(l => !string.IsNullOrWhiteSpace(l)); // remove empty lines
                    args = lines.Concat(args).ToArray();
                });

                args.ProcessArg("-outdir", o =>
                {
                    outputDir = o;
                });

                MapSource mapSource = MapSource.Create;

                args.ProcessArg("-testpalette", s =>
                {
                    testColors.AddRange(Utils.GetNamedPalette(s));
                });
                args.ProcessArg("-testcolor", s =>
                {
                    testColors.Add(System.Drawing.ColorTranslator.FromHtml(s));
                });

                args.ProcessArg("-partitions", s =>
                {
                    if (s.Contains('x'))
                    {
                        partitionsPerDimension = int.Parse(s.Split('x')[0]);
                        partitionDepth         = int.Parse(s.Split('x')[1]);
                    }
                    else
                    {
                        partitionsPerDimension = int.Parse(s);
                    }
                });

                args.ProcessArg("-processImagesInDir", o =>
                {
                    var files = System.IO.Directory.EnumerateFiles(o, "*", System.IO.SearchOption.TopDirectoryOnly);
                    foreach (var file in files)
                    {
                        processImages.Add(file);
                    }
                });

                args.ProcessArg("-processImage", o =>
                {
                    processImages.Add(o);
                });

                args.ProcessArg("-cores", o =>
                {
                    int a = int.Parse(o);
                    if (a < 1)
                    {
                        a = System.Environment.ProcessorCount - a;
                    }
                    coresToUtilize = a;
                });

                FontFamilyFontProvider fontFamilyProvider = null;

                args.ProcessArg("-fonttype", s =>
                {
                    switch (s.ToLowerInvariant())
                    {
                    case "mono":
                        fontProvider = MonoPaletteFontProvider.ProcessArgs(args);
                        break;

                    case "normal":
                        fontProvider = FontProvider.ProcessArgs(args);
                        break;

                    case "colorkey":
                        fontProvider = ColorKeyFontProvider.ProcessArgs(args);
                        break;

                    case "fontfamily":
                        fontProvider = fontFamilyProvider = FontFamilyFontProvider.ProcessArgs(args);
                        break;

                    default:
                        throw new Exception("Unknown font type: " + s);
                    }
                });

                args.ProcessArg("-pf", s =>
                {
                    switch (s.ToLowerInvariant())
                    {
                    case "square":
                        pixelFormat = SquareLCCPixelFormat.ProcessArgs(args);// HSLPixelFormat.ProcessArgs(args);
                        break;

                    default:
                    case "fivetile":
                        pixelFormat = FiveTilePixelFormat.ProcessArgs(args, fontProvider);
                        break;
                    }
                });

                if (pixelFormat == null)
                {
                    Log.WriteLine("Pixel format not specified.");
                    return;
                    //pixelFormat = NaiveYUVPixelFormat.ProcessArgs(args);
                }
                // emoji12-C64_YUV-2v5x5+2
                if (fontProvider == null)
                {
                    Log.WriteLine("Font information not specified.");
                    return;
                }
                if (pixelFormat == null)
                {
                    Log.WriteLine("Pixel format not specified.");
                    return;
                }

                args.ProcessArg("-calcn", s =>
                {
                    ulong maxMapKeys = ulong.Parse(s);

                    //partitionManager.Init();

                    //ulong partitionCount = (ulong)partitionManager.PartitionCount;
                    //Log.WriteLine("Partition count: {0:N0}", partitionCount);

                    // so the thing about partition count. You can't just divide by partition count,
                    // because in deeper levels most partitions are simply unused / empty.
                    // a decent conservative approximation is to take the first N levels
                    //partitionCount = (ulong)Math.Pow(partitionManager.PartitionsPerDimension, 2.5);// n = 2.5
                    //Log.WriteLine("Adjusted partition count: {0:N0}", partitionCount);
                    Log.WriteLine("Charset count: {0:N0}", fontProvider.CharCount);
                    Log.WriteLine("Cores to utilize: {0:N0}", coresToUtilize);
                    Log.WriteLine("Luma + chroma components: {0:N0}", pixelFormat.DimensionCount);

                    ulong NbasedOnMapSize = (ulong)Math.Floor(Math.Pow(maxMapKeys, 1.0 / pixelFormat.DimensionCount));

                    Log.WriteLine("======================");
                    Log.WriteLine("== THEREFORE, use N={0:N0}", NbasedOnMapSize);
                    Log.WriteLine("======================");

                    System.Environment.Exit(0);
                });

                if (outputDir == null)
                {
                    Log.WriteLine("No output directory was specified.");
                    return;
                }
                outputDir = System.IO.Path.GetFullPath(outputDir);
                Log.WriteLine("Output directory: {0}", outputDir);

                if (!System.IO.Directory.Exists(outputDir))
                {
                    System.IO.Directory.CreateDirectory(outputDir);
                }

                args.ProcessArg("-loadmap", _ =>
                {
                    mapSource = MapSource.Load;
                    // if you're loading, then we want to process the args from that directory.
                    //outputDir = System.IO.Path.GetDirectoryName(s);
                    string argspath = System.IO.Path.Combine(outputDir, "args.txt");
                    var lines       = System.IO.File.ReadAllLines(argspath)
                                      .Select(l => l.Split('#')[0])               // remove comments
                                      .Where(l => !string.IsNullOrWhiteSpace(l)); // remove empty lines
                    args = lines.Concat(args).ToArray();
                });

                string partitionConfigTag = string.Format("p{0}x{1}", partitionsPerDimension, partitionDepth.HasValue ? partitionDepth.ToString() : "N");

                string configTag = string.Format("{0}_{1}_{2}", fontProvider.DisplayName, pixelFormat.PixelFormatString, partitionConfigTag);
                outputDir = System.IO.Path.Combine(outputDir, configTag);
                Log.WriteLine("Ensuring directory exists: {0}", outputDir);
                System.IO.Directory.CreateDirectory(outputDir);

                string logPath = System.IO.Path.Combine(outputDir, "log.txt");
                Log.SetLogFile(logPath);

                string infopath    = System.IO.Path.Combine(outputDir, "args.txt");
                string mapFullPath = System.IO.Path.Combine(outputDir, string.Format("mapfull_{0}.png", configTag));
                string mapRefPath  = System.IO.Path.Combine(outputDir, string.Format("mapref_{0}.png", configTag));
                string mapFontPath = System.IO.Path.Combine(outputDir, string.Format("mapfont_{0}.png", configTag));

                args.ProcessArg("-loadOrCreateMap", _ =>
                {
                    if (System.IO.File.Exists(mapRefPath) && System.IO.File.Exists(mapFontPath))
                    {
                        Log.WriteLine("-loadOrCreateMap: Loading existing map.");
                        mapSource = MapSource.Load;
                    }
                    else
                    {
                        Log.WriteLine("-loadOrCreateMap: Looks like we have to create the map.");
                        mapSource = MapSource.Create;
                    }
                });

                if (mapSource == MapSource.Create)
                {
                    using (var infoFile = new StreamWriter(infopath))
                    {
                        foreach (var arg in args)
                        {
                            infoFile.WriteLine(arg);
                        }
                    }
                }

                HybridMap2 map = null;

                switch (mapSource)
                {
                case MapSource.Create:
                    Log.EnterTask("--- MAP GENERATION");
                    map = new HybridMap2(fontProvider, pixelFormat,
                                         mapFullPath,
                                         mapRefPath,
                                         mapFontPath,
                                         coresToUtilize, partitionsPerDimension, partitionDepth);
                    Log.EndTask();
                    break;

                case MapSource.Load:
                    Log.EnterTask("--- MAP LOAD");
                    map = HybridMap2.LoadFromDisk(outputDir, fontProvider, pixelFormat);
                    Log.EndTask();
                    break;
                }

                if (fontFamilyProvider != null)
                {
                    //string fontImgPath = System.IO.Path.Combine(outputDir, "font.png");
                    //fontFamilyProvider.SaveFontImage(fontImgPath);
                }

                Log.EnterTask("processing images");

                foreach (var c in testColors)
                {
                    map.TestColor(outputDir, ColorF.From(c));
                }

                using (var refMapImage = new Bitmap(mapRefPath))
                    using (var refFontImage = new Bitmap(mapFontPath))
                    {
                        foreach (var file in processImages)
                        {
                            Log.WriteLine("Processing {0}", file);
                            string destFile  = string.Format("test-{0}.png", System.IO.Path.GetFileNameWithoutExtension(file));
                            string destfullp = System.IO.Path.Combine(outputDir, destFile);
                            using (var testImg = new Bitmap(file))
                            {
                                var rv = map.ProcessImageUsingRef(refMapImage, refFontImage, testImg, destfullp);
                                if (fontFamilyProvider != null)
                                {
                                    string str     = fontFamilyProvider.ConvertToText(rv);
                                    string txtpath = System.IO.Path.Combine(outputDir, string.Format("test-{0}.txt", System.IO.Path.GetFileNameWithoutExtension(file)));
                                    System.IO.File.WriteAllText(txtpath, str);
                                }
                            }
                        }
                    }
                Log.EndTask();

#if !DEBUG
            }
            catch (Exception e)
            {
                Log.WriteLine("Exception occurred:\r\n{0}", e);
            }
#else
            }