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(); }
// 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(); }
// 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(); }