private static Bitmap DrawPieChart(byte[] colorIds, bool[] enabledColorRegions, int size, int pieSize) { int pieAngle = enabledColorRegions?.Count(c => c) ?? Species.ColorRegionCount; pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1); int pieNr = 0; Bitmap bm = new Bitmap(size, size); using (Graphics graph = Graphics.FromImage(bm)) { graph.SmoothingMode = SmoothingMode.AntiAlias; for (int c = 0; c < Species.ColorRegionCount; c++) { if (enabledColorRegions?[c] ?? true) { if (colorIds[c] > 0) { using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c]))) { graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize, pieNr * pieAngle + 270, pieAngle); } } pieNr++; } } using (var pen = new Pen(Color.Gray)) graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize); } return(bm); }
public static string RegionColorInfo(Species species, byte[] colorIds) { if (species == null || colorIds == null) { return(null); } var creatureRegionColors = new StringBuilder("Colors:"); var cs = species.colors; for (int r = 0; r < Species.ColorRegionCount; r++) { if (!string.IsNullOrEmpty(cs[r]?.name)) { creatureRegionColors.Append($"\n{cs[r].name} ({r}): {CreatureColors.CreatureColorName(colorIds[r])} ({colorIds[r]})"); } } return(creatureRegionColors.ToString()); }
/// <summary> /// Creates a colored species image and saves it as cache file. Returns true when created successful. /// </summary> /// <returns></returns> private static bool CreateAndSaveCacheSpeciesFile(byte[] colorIds, bool[] enabledColorRegions, string speciesBaseImageFilePath, string speciesColorMaskFilePath, string cacheFilePath, int outputSize = 256) { if (string.IsNullOrEmpty(cacheFilePath) || !File.Exists(speciesBaseImageFilePath)) { return(false); } using (Bitmap bmpBaseImage = new Bitmap(speciesBaseImageFilePath)) using (Bitmap bmpColoredCreature = new Bitmap(bmpBaseImage.Width, bmpBaseImage.Height, PixelFormat.Format32bppArgb)) using (Graphics graph = Graphics.FromImage(bmpColoredCreature)) { bool imageFine = true; graph.SmoothingMode = SmoothingMode.AntiAlias; //// ellipse background shadow const int scx = TemplateSize / 2; const int scy = (int)(scx * 1.6); const double perspectiveFactor = 0.3; const int yStart = scy - (int)(perspectiveFactor * .7 * scx); const int yEnd = (int)(2 * perspectiveFactor * scx); GraphicsPath pathShadow = new GraphicsPath(); pathShadow.AddEllipse(0, yStart, TemplateSize, yEnd); var colorBlend = new ColorBlend { Colors = new[] { Color.FromArgb(0), Color.FromArgb(40, 0, 0, 0), Color.FromArgb(80, 0, 0, 0) }, Positions = new[] { 0, 0.6f, 1 } }; using (var pthGrBrush = new PathGradientBrush(pathShadow) { InterpolationColors = colorBlend }) graph.FillEllipse(pthGrBrush, 0, yStart, TemplateSize, yEnd); // background shadow done // if species has color regions, apply colors if (File.Exists(speciesColorMaskFilePath)) { var rgb = new byte[Species.ColorRegionCount][]; var useColorRegions = new bool[Species.ColorRegionCount]; for (int c = 0; c < Species.ColorRegionCount; c++) { useColorRegions[c] = enabledColorRegions[c] && colorIds[c] != 0; if (useColorRegions[c]) { Color cl = CreatureColors.CreatureColor(colorIds[c]); rgb[c] = new[] { cl.R, cl.G, cl.B }; } } imageFine = ApplyColorsUnsafe(rgb, useColorRegions, speciesColorMaskFilePath, TemplateSize, bmpBaseImage); } if (imageFine) { // draw species image on background graph.DrawImage(bmpBaseImage, 0, 0, TemplateSize, TemplateSize); string cacheFolder = Path.GetDirectoryName(cacheFilePath); if (string.IsNullOrEmpty(cacheFolder)) { return(false); } if (!Directory.Exists(cacheFolder)) { Directory.CreateDirectory(cacheFolder); } if (outputSize == TemplateSize) { return(SaveBitmapToFile(bmpColoredCreature, cacheFilePath)); } using (var resized = new Bitmap(outputSize, outputSize)) using (var g = Graphics.FromImage(resized)) { g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.SmoothingMode = SmoothingMode.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.DrawImage(bmpColoredCreature, 0, 0, outputSize, outputSize); return(SaveBitmapToFile(resized, cacheFilePath)); } } } return(false); }
/// <summary> /// Returns a bitmap image that represents the given colors. If a species color file is available, that is used, else a pic-chart like representation. /// </summary> /// <param name="colorIds"></param> /// <param name="species"></param> /// <param name="enabledColorRegions"></param> /// <param name="size"></param> /// <param name="pieSize"></param> /// <param name="onlyColors">Only return a pie-chart like color representation.</param> /// <param name="onlyImage">Only return an image of the colored creature. If that's not possible, return null.</param> /// <param name="creatureSex">If given, it's tried for find a sex-specific image.</param> /// <returns></returns> public static Bitmap GetColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool onlyImage = false, Sex creatureSex = Sex.Unknown) { if (colorIds == null) { colorIds = new int[Species.ColorRegionCount]; } string speciesName = SpeciesImageName(species?.name); // check if there are sex specific images if (creatureSex != Sex.Unknown) { string speciesNameWithSex; switch (creatureSex) { case Sex.Female: speciesNameWithSex = speciesName + "F"; if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension))) { speciesName = speciesNameWithSex; } break; case Sex.Male: speciesNameWithSex = speciesName + "M"; if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension))) { speciesName = speciesNameWithSex; } break; } } string speciesBackgroundFilePath = Path.Combine(ImgFolder, speciesName + Extension); string speciesColorMaskFilePath = Path.Combine(ImgFolder, speciesName + "_m" + Extension); string cacheFilePath = ColoredCreatureCacheFilePath(speciesName, colorIds); bool cacheFileExists = File.Exists(cacheFilePath); if (!onlyColors && !cacheFileExists) { cacheFileExists = CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFilePath); } if (onlyImage && !cacheFileExists) { return(null); // creating the species file failed } if (cacheFileExists && size == TemplateSize) { try { return(new Bitmap(cacheFilePath)); } catch { // cached file corrupted, recreate if (CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFilePath)) { try { return(new Bitmap(cacheFilePath)); } catch { // file is still invalid after recreation, ignore file } } } return(null); } Bitmap bm = new Bitmap(size, size); using (Graphics graph = Graphics.FromImage(bm)) { graph.SmoothingMode = SmoothingMode.AntiAlias; if (cacheFileExists) { graph.CompositingMode = CompositingMode.SourceCopy; graph.CompositingQuality = CompositingQuality.HighQuality; graph.InterpolationMode = InterpolationMode.HighQualityBicubic; graph.SmoothingMode = SmoothingMode.HighQuality; graph.PixelOffsetMode = PixelOffsetMode.HighQuality; try { using (var cachedImgBmp = new Bitmap(cacheFilePath)) graph.DrawImage(cachedImgBmp, 0, 0, size, size); } catch { // cached file invalid, recreate if (CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFilePath)) { try { using (var cachedImgBmp = new Bitmap(cacheFilePath)) graph.DrawImage(cachedImgBmp, 0, 0, size, size); } catch { // file is still invalid after recreation, ignore file bm.Dispose(); return(null); } } } } else { // draw pieChart int pieAngle = enabledColorRegions?.Count(c => c) ?? Species.ColorRegionCount; pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1); int pieNr = 0; for (int c = 0; c < Species.ColorRegionCount; c++) { if (enabledColorRegions?[c] ?? true) { if (colorIds[c] > 0) { using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c]))) { graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize, pieNr * pieAngle + 270, pieAngle); } } pieNr++; } } using (var pen = new Pen(Color.Gray)) graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize); } } return(bm); }