Esempio n. 1
0
        internal void OutputFullMap(string MapFullPath, Mapping[] Map)
        {
            int  numCellsX    = (int)Math.Ceiling(Math.Sqrt(this.Keys.Count()));
            Size mapImageSize = Utils.Mul(FontProvider.CharSizeNoPadding, numCellsX);

            Log.WriteLine("MAP image generation...");
            Log.WriteLine("  Cells: [" + numCellsX + ", " + numCellsX + "]");
            Log.WriteLine("  Image size: [" + mapImageSize.Width + ", " + mapImageSize.Height + "]");

            if (mapImageSize.Width > 17000)
            {
                // a healthy safe amount.
                // https://stackoverflow.com/questions/29175585/what-is-the-maximum-resolution-of-c-sharp-net-bitmap
                Log.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                Log.WriteLine("!!! full map generation not possible; too big.");
                Log.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                return;
            }

            var        FullMapBitmap = new Bitmap(mapImageSize.Width, mapImageSize.Height, PixelFormat.Format24bppRgb);
            BitmapData destData      = FullMapBitmap.LockBits(new Rectangle(0, 0, mapImageSize.Width, mapImageSize.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            ProgressReporter pr = new ProgressReporter(Keys.Length);

            foreach (ValueSet k in Keys)
            {
                pr.Visit();
                CharInfo ci = this.CharInfo[Map[k.ID].icharInfo];

                long cellY = k.ID / numCellsX;
                long cellX = k.ID - (numCellsX * cellY);

                FontProvider.BlitCharacter(ci.srcIndex, destData, cellX * FontProvider.CharSizeNoPadding.Width, cellY * FontProvider.CharSizeNoPadding.Height);
            }

            FullMapBitmap.UnlockBits(destData);

            FullMapBitmap.Save(MapFullPath);
            FullMapBitmap.Dispose();
        }
Esempio n. 2
0
        // each R,G,B value of the resulting image is a mapping. the inserted value 0-1 refers to a character
        // in the font texture.
        internal unsafe void OutputRefMapAndFont(string MapRefPath, string MapRefFontPath, Mapping[] Map)
        {
            Log.WriteLine("FONT MAP image generation...");
            float fontMapCharCount = DistinctMappedChars.Length;

            Log.WriteLine("  Entries linear: " + fontMapCharCount);
            long fontImgPixels = DistinctMappedChars.Length * FontProvider.CharSizeNoPadding.Width * FontProvider.CharSizeNoPadding.Height;

            Log.WriteLine("  Total pixels: " + fontImgPixels);
            int fontImgWidthChars   = (int)Math.Ceiling(Math.Sqrt(fontImgPixels) / FontProvider.CharSizeNoPadding.Width);
            int fontImgWidthPixels  = fontImgWidthChars * FontProvider.CharSizeNoPadding.Width;
            int fontImgHeightChars  = (int)Math.Ceiling((double)fontImgPixels / fontImgWidthPixels / FontProvider.CharSizeNoPadding.Height);
            int fontImgHeightPixels = fontImgHeightChars * FontProvider.CharSizeNoPadding.Height;

            Log.WriteLine("  Image size chars: [" + fontImgWidthChars + ", " + fontImgHeightChars + "]");
            Log.WriteLine("  Image size pixels: [" + fontImgWidthPixels + ", " + fontImgHeightPixels + "]");

            var        fontBmp      = new Bitmap(fontImgWidthPixels, fontImgHeightPixels, PixelFormat.Format24bppRgb);
            BitmapData destFontData = fontBmp.LockBits(new Rectangle(0, 0, fontImgWidthPixels, fontImgHeightPixels), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            foreach (var ci in DistinctMappedChars)
            {
                long cellY = ci.refFontIndex / fontImgWidthChars;
                long cellX = ci.refFontIndex - (fontImgWidthChars * cellY);

                FontProvider.BlitCharacter(ci.srcIndex, destFontData, (cellX * FontProvider.CharSizeNoPadding.Width), (cellY * FontProvider.CharSizeNoPadding.Height));
            }

            fontBmp.UnlockBits(destFontData);

            fontBmp.Save(MapRefFontPath);
            fontBmp.Dispose();
            fontBmp = null;

            // NOW generate the small ref map. since we aim to support >65k fonts, we can't just use
            // a single R/G/B val for an index. there's just not enough precision. The most precise PNG format is 16-bit grayscale.
            // we should just aim to use RGB as 8-bit values, so each pixel is an encoded
            // 24-bit char index.

            double pixelCountD = Math.Ceiling((double)Keys.Length);

            int mapWidthPixels  = (int)Math.Ceiling(Math.Sqrt(pixelCountD));
            int mapHeightPixels = (int)Math.Ceiling(pixelCountD / mapWidthPixels);

            Log.WriteLine("REF MAP image generation...");
            Log.WriteLine("  Image size: [" + mapWidthPixels + ", " + mapHeightPixels + "]");

            var        refMapBmp = new Bitmap(mapWidthPixels, mapHeightPixels, PixelFormat.Format24bppRgb);
            BitmapData destData  = refMapBmp.LockBits(new Rectangle(0, 0, mapWidthPixels, mapHeightPixels), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            for (int i = 0; i < Keys.Length; ++i)
            {
                CharInfo ci = this.CharInfo[Map[i].icharInfo];
                int      y  = i / mapWidthPixels;
                int      x  = i - (y * mapWidthPixels);
                Color    c  = RefFontIndexToColor(ci.refFontIndex);
                destData.SetPixel(x, y, c);
            }

            refMapBmp.UnlockBits(destData);

            refMapBmp.Save(MapRefPath);
            refMapBmp.Dispose();
        }
Esempio n. 3
0
        // when a color looks wrong, let's try and trace it back. outputs mapping information for this color,
        // top char matches, and outputs an image showing the chars found.
        public void TestColor(string outputDir, ColorF rgb, params Point[] charPixPosWUT)
        {
            if (this.Keys == null)
            {
                Log.WriteLine("Keys is not yet populated. Need to generate them....");
                this.Keys = Utils.Permutate(PixelFormatProvider.DimensionCount, PixelFormatProvider.DiscreteNormalizedValues); // returns sorted.
            }
            const int charsToOutputToImage   = 100;
            const int charsToOutputInConsole = 1;
            const int detailedCharOutput     = 0;

            List <int> WUTcharIndex = new List <int>();

            foreach (Point p in charPixPosWUT)
            {
                WUTcharIndex.Add(this.FontProvider.GetCharIndexAtPixelPos(p));
            }

            Log.WriteLine("Displaying debug info about color");
            Log.WriteLine("  src : " + rgb);
            int mapid = this.PixelFormatProvider.DebugGetMapIndexOfColor(rgb);

            Log.WriteLine("  which lands in mapID: " + mapid);
            Log.WriteLine("   -> " + this.Keys[mapid]);

            // now display top N characters for that mapid.
            MappingArray marr = new MappingArray();

            Utils.ValueRangeInspector r = new Utils.ValueRangeInspector();
            foreach (CharInfo ci in this.CharInfo)
            {
                Mapping m;
                m.icharInfo = ci.srcIndex;
                m.imapKey   = mapid;
                m.dist      = PixelFormatProvider.CalcKeyToColorDist(this.Keys[mapid], ci.actualValues);
                r.Visit(m.dist);

                if (WUTcharIndex.Contains(ci.srcIndex))
                {
                    Log.WriteLine("      You want data about char {0} well here it is:", ci);
                    Log.WriteLine("        dist: {0,6:0.00} to char {1}", m.dist, ci);
                    double trash = PixelFormatProvider.CalcKeyToColorDist(this.Keys[mapid], ci.actualValues, true);
                }

                marr.Add(m);
            }

            marr.Sort();

            Bitmap bmp = new Bitmap(FontProvider.CharSizeNoPadding.Width * charsToOutputToImage, FontProvider.CharSizeNoPadding.Height * 2);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.FillRectangle(new SolidBrush(Color.FromArgb((int)rgb.R, (int)rgb.G, (int)rgb.B)), 0, 0, bmp.Width, bmp.Height);
            }

            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, FontProvider.CharSizeNoPadding.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            if (charsToOutputInConsole > 0)
            {
                Log.WriteLine("    listing top {0} closest characters to that map key:", charsToOutputInConsole);
            }
            int i = 0;

            foreach (var mapping in marr.GetEnumerator())
            {
                if (i < charsToOutputInConsole)
                {
                    Log.WriteLine("      dist: {0,6:0.00} to char {1}", mapping.dist, this.CharInfo[mapping.icharInfo]);
                    double dist = PixelFormatProvider.CalcKeyToColorDist(this.Keys[mapid], this.CharInfo[mapping.icharInfo].actualValues, i < detailedCharOutput);
                }
                if (i >= charsToOutputToImage)
                {
                    break;
                }
                FontProvider.BlitCharacter(mapping.icharInfo, bmpData, FontProvider.CharSizeNoPadding.Width * i, 0);
                i++;
            }
            bmp.UnlockBits(bmpData);

            string path = System.IO.Path.Combine(outputDir, string.Format("TESTVIS {0}.png", rgb));

            Log.WriteLine("    Output chars to :" + path);
            bmp.Save(path);
            bmp.Dispose();
        }
Esempio n. 4
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
            }