static int Main(string[] astrArgs) { if (astrArgs.Length != 2) { Usage(); return 1; } Palette pal; try { pal = new Palette(astrArgs[0]); } catch (Exception ex) { Console.WriteLine(ex); return 1; } BinaryWriter binw = new BinaryWriter(new FileStream(astrArgs[1], FileMode.Create)); binw.Write((byte)((pal.Length & 0xff00) >> 8)); binw.Write((byte)(pal.Length & 0xff)); for (int i = 0; i < pal.Length; i++) { binw.Write(pal[i].R); binw.Write(pal[i].G); binw.Write(pal[i].B); } binw.Close(); return 0; }
static int Main(string[] astrArgs) { if (astrArgs.Length < 3) { Console.WriteLine("Usage:\nbscale -scale <scale> -pal <palette.pal> <file(s) ...> -out <outdir>\n"); return -1; } double nScale = 1.0; string strOutDir = null, strPalette = null; ArrayList alFileSpecs = new ArrayList(); for (int iarg = 0; iarg < astrArgs.Length; iarg++) { if (astrArgs[iarg][0] == '-') { switch (astrArgs[iarg]) { case "-scale": nScale = double.Parse(astrArgs[++iarg]); break; case "-out": strOutDir = astrArgs[++iarg]; break; case "-pal": strPalette = astrArgs[++iarg]; break; } } else { alFileSpecs.Add(astrArgs[iarg]); } } // Read in the palette Palette pal = new Palette(strPalette); if (pal == null) { Console.WriteLine("Error: unable to read the palette file {0}\n", strPalette); return -1; } foreach (string strFileSpec in alFileSpecs) { Console.WriteLine("dir = " + Path.GetDirectoryName(strFileSpec) + ", file = " + Path.GetFileName(strFileSpec)); string[] astrFiles = Directory.GetFiles(Path.GetDirectoryName(strFileSpec), Path.GetFileName(strFileSpec)); foreach (string strFile in astrFiles) { Console.WriteLine(strFile); Bitmap bm = new Bitmap(strFile); Bitmap bmScaled = TBitmapTools.ScaleBitmap(bm, nScale, pal); if (!Directory.Exists(strOutDir)) Directory.CreateDirectory(strOutDir); bmScaled.Save(strOutDir + Path.DirectorySeparatorChar + Path.GetFileName(strFile), bm.RawFormat); } } return 0; }
public static Bitmap ScaleBitmap(Bitmap bm, double nScale, Palette palFixed) { Color[] aclrSpecial = new Color[] { // side colors Color.FromArgb(0, 116, 232), Color.FromArgb(0, 96, 196), Color.FromArgb(0, 64, 120), Color.FromArgb(0, 48, 92), Color.FromArgb(0, 32, 64), // transparent Color.FromArgb(255, 0, 255), // shadow Color.FromArgb(156, 212, 248), }; Bitmap bmNew = new Bitmap((int)Math.Floor(bm.Width * nScale + 0.5), (int)Math.Floor(bm.Height * nScale + 0.5)); for (int y = 0; y < bmNew.Height; y++) { for (int x = 0; x < bmNew.Width; x++) { double nWidthRatio = (double)bm.Width / (double)bmNew.Width; double xLeft = (double)x * nWidthRatio; double nHeightRatio = (double)bm.Height / (double)bmNew.Height; double yTop = (double)y * nHeightRatio; double xRight = xLeft + 1.0 * nWidthRatio; if (xRight > bm.Width) xRight = bm.Width; double yBottom = yTop + 1.0 * nHeightRatio; if (yBottom > bm.Height) yBottom = bm.Height; DoubleRect drc = new DoubleRect(xLeft, yTop, xRight, yBottom); Color clrSample = SampleGobBitmap(bm, drc, aclrSpecial, 4); if (palFixed != null) { bool fSpecial = false; foreach (Color clrSpecial in aclrSpecial) { if (clrSample == clrSpecial) { fSpecial = true; break; } } if (!fSpecial) clrSample = palFixed[palFixed.FindClosestEntry(clrSample)]; } bmNew.SetPixel(x, y, clrSample); } } return bmNew; }
static int Main(string[] astrArgs) { if (astrArgs.Length < 1) { Console.WriteLine("pal2act usage:\npal2act <palette.pal> [out.act]"); return -1; } string strIn = astrArgs[0]; string strOut; if (astrArgs.Length < 2) { strOut = Path.ChangeExtension(strIn, ".act"); } else { strOut = astrArgs[1]; } Palette pal = new Palette(strIn); pal.SavePhotoshopAct(strOut); return 0; }
public static unsafe void Save(string strFile, Palette pal, string strFileOut) { Bitmap bm = new Bitmap(strFile); // Find the palette index for black int iclrBlack = pal.FindClosestEntry(Color.FromArgb(0, 0, 0)); // Lock down bits for speed Rectangle rc = new Rectangle(0, 0, bm.Width, bm.Height); BitmapData bmd = bm.LockBits(rc, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); byte *pbBase = (byte *)bmd.Scan0.ToPointer(); // Map all the pixels in the bitmap to 'nearest' color palette indices byte[] ab = new byte[((bm.Width + 1) & ~1) * bm.Height]; int i = 0; for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { byte *pb = pbBase + y * bmd.Stride + x * 3; Color clr = Color.FromArgb(pb[2], pb[1], pb[0]); if (clr == Color.FromArgb(156, 212, 248)) clr = Color.FromArgb(0, 0, 0); ab[i++] = (byte)pal.FindClosestEntry(clr); } if ((bm.Width & 1) == 1) ab[i++] = (byte)iclrBlack; } bm.UnlockBits(bmd); // Write bitmap header, bits BinaryWriter bwtr = new BinaryWriter(new FileStream(strFileOut, FileMode.Create, FileAccess.Write)); bwtr.Write(Misc.SwapUShort((ushort)((bm.Width + 1) & ~1))); bwtr.Write(Misc.SwapUShort((ushort)bm.Height)); bwtr.Write(ab); bwtr.Close(); // Done bm.Dispose(); }
static unsafe void Main(string[] args) { // Get parameters Palette palIn = new Palette(args[0]); string strFileOut = args[1]; double dAlpha = Double.Parse(args[2]); // Create mapping byte[] ab = new byte[palIn.Length]; Palette palInHSB = new Palette(palIn.Length); for (int iclr = 0; iclr < palIn.Length; iclr++) { Color clr = palIn[iclr]; double h = clr.GetHue(); double s = clr.GetSaturation(); double l = clr.GetBrightness(); double r; double g; double b; MyHSLtoRGB(h, s, l * dAlpha, &r, &g, &b); Color clrShadow = Color.FromArgb((int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0)); ab[iclr] = (byte)palIn.FindClosestEntry(clrShadow); } // Write palette mapping Stream stm = new FileStream(strFileOut, FileMode.Create, FileAccess.Write, FileShare.None); BinaryWriter bwtr = new BinaryWriter(stm); bwtr.Write(ab); bwtr.Close(); #if false // Check it Palette palCheck = new Palette(palIn.Length); for (int iclr = 0; iclr < palIn.Length; iclr++) palCheck[iclr] = palIn[ab[iclr]]; palCheck.SaveJasc("shadow.pal"); #endif }
static Palette QuantizeColors2(ArrayList alsColors, Palette palFixed, int cPalEntries, int cPalEntriesFixed) { // If no quantization needed (4 bit grayscale), return if (cPalEntriesFixed >= cPalEntries) return palFixed; MedianCut mcut = new MedianCut(alsColors); mcut.convert(cPalEntries - cPalEntriesFixed); Palette palUpper = mcut.GetPalette(); palUpper.Pad(cPalEntries, Color.FromArgb(255, 0, 255)); Color[] aclr = new Color[cPalEntries]; for (int iclr = 0; iclr < cPalEntriesFixed; iclr++) aclr[iclr] = palFixed[iclr]; for (int iclr = cPalEntriesFixed; iclr < cPalEntries; iclr++) { Color clr = palUpper[iclr - cPalEntriesFixed]; Color clrT = Color.FromArgb(clr.R & 0xfc, clr.G & 0xfc, clr.B & 0xfc); aclr[iclr] = clrT; } return new Palette(aclr); }
public static void QuantizeTemplates(TemplateDoc tmpd, Palette palFixed, int cPalEntries, int cPalEntriesFixed, int cPalEntriesBackground) { // Load the fixed palette. The result will be 24 bit templates normalized to a palette of 256 colors, // the "fixed" palette plus a quantized palette. if (palFixed == null) { palFixed = Palette.OpenDialog(null); if (palFixed == null) { MessageBox.Show(DocManager.GetFrameParent(), "Must have the fixed color palette to continue!"); return; } switch (palFixed.Length) { case 16: cPalEntries = 16; cPalEntriesFixed = 16; cPalEntriesBackground = 0; break; case 256: cPalEntries = 256; cPalEntriesFixed = 128; cPalEntriesBackground = 32; break; } } // Quantize loop. Designed to make optimal use of the lower 128 fixed colors // Quantize background separately from foreground Template tmplBackground = tmpd.GetBackgroundTemplate(); if (tmplBackground != null && cPalEntriesBackground != 0) { // Create a despeckled hue map of the background. We'll use this to // subtract background from foreground so we can quantize foreground separately Bitmap bmHueBackground = MakeHueMap(tmplBackground.Bitmap); DespeckleGrayscaleBitmap(bmHueBackground, 9, 50); // Calc mean and standard deviation for filtering purposes double nMean = CalcGrayscaleMean(bmHueBackground); double nStdDev = CalcGrayscaleStandardDeviation(bmHueBackground, nMean); // Add extract & quantize the background pixels ArrayList alsColorsBackground = new ArrayList(); AddTemplateColors(alsColorsBackground, tmplBackground.Bitmap); palFixed = QuantizeColors(alsColorsBackground, palFixed, cPalEntriesFixed + cPalEntriesBackground, cPalEntriesFixed); cPalEntriesFixed += cPalEntriesBackground; // Now extract foreground pixels by first subtracting background pixels ArrayList alsColorsForeground = new ArrayList(); Template[] atmpl = tmpd.GetTemplates(); foreach (Template tmpl in atmpl) { if (tmpl == tmplBackground) continue; Bitmap bmT = MakeHueMap(tmpl.Bitmap); DespeckleGrayscaleBitmap(bmT, 9, 50); SubtractGrayscaleDistribution(bmT, nMean, nStdDev); for (int y = 0; y < bmT.Height; y++) { for (int x = 0; x < bmT.Width; x++) { Color clr = bmT.GetPixel(x, y); if (clr != Color.FromArgb(255, 0, 255)) bmT.SetPixel(x, y, tmpl.Bitmap.GetPixel(x, y)); } } AddTemplateColors(alsColorsForeground, bmT); } // Now quantize foreground pixels // Set the palette and color match Palette palNew = QuantizeColors(alsColorsForeground, palFixed, cPalEntries, cPalEntriesFixed); tmpd.SetPalette(palNew, true); } else { // No background template; just quantize everything together Template[] atmpl = tmpd.GetTemplates(); ArrayList alsColors = new ArrayList(); foreach (Template tmpl in atmpl) AddTemplateColors(alsColors, tmpl.Bitmap); // Now quantize foreground pixels // Set the palette and color match Palette palNew = QuantizeColors(alsColors, palFixed, cPalEntries, cPalEntriesFixed); tmpd.SetPalette(palNew, true); } }
public TBitmap(Bitmap bm, Palette pal) { m_pal = pal; Init(bm); }
public static void SaveFont(string strFileBitmap, Palette pal, string strFileAscii, string strFileSave) { // Get the character order TextReader tr = new StreamReader(strFileAscii); string strAscii = tr.ReadLine(); tr.Close(); // Get the character count int cch = strAscii.Length; // Load the image, lose scaling factor Bitmap bmFile = new Bitmap(strFileBitmap); Bitmap bm = Misc.NormalizeBitmap(bmFile); bmFile.Dispose(); // Turn this on to see the character -> glyph mapping as it happens (help for // finding 'font bugs'). Set a breakpoint below on frm.Dispose(). #if SHOWFONT Form frm = new Form(); frm.Height = 1000; frm.Show(); Graphics gT = frm.CreateGraphics(); gT.InterpolationMode = InterpolationMode.NearestNeighbor; int yDst = 0; int xDst = 0; #endif // Scan the bitmap for widths int xLast = 0; int ich = 0; byte[] acxChar = new byte[256]; for (int x = 0; x < bm.Width; x++) { if (bm.GetPixel(x, 0) != Color.FromArgb(255, 0, 255)) { Debug.Assert(ich < cch); acxChar[strAscii[ich]] = (byte)(x - xLast); #if SHOWFONT gT.DrawString(strAscii[ich].ToString(), frm.Font, new SolidBrush(frm.ForeColor), new PointF(xDst, yDst)); Rectangle rcDst = new Rectangle(xDst + 20, yDst + 2, (x - xLast), bm.Height); Rectangle rcSrc = new Rectangle(xLast, 1, x - xLast, bm.Height); gT.DrawImage(bm, rcDst, rcSrc, GraphicsUnit.Pixel); yDst += Math.Max(bm.Height, frm.Font.Height); if (yDst > frm.ClientRectangle.Height) { xDst += 50; yDst = 0; } gT.Flush(); Application.DoEvents(); #endif ich++; xLast = x; } } #if SHOWFONT gT.Dispose(); frm.Dispose(); #endif if (ich != cch) { MessageBox.Show(String.Format("Expecting {0} characters but found {2}{1}.", cch, ich, ich < cch ? "only " : ""), "bcr2 - Font Compilation Error"); Debug.Assert(ich == cch - 1); } int cy = bm.Height - 1; // Save serialization ArrayList alsSdEven = new ArrayList(); int xT = 0; int ichDefault = -1; for (ich = 0; ich < cch; ich++) { // ? is the default "no glyph" character if (strAscii[ich] == '?') ichDefault = ich; // Get subimage int cx = acxChar[strAscii[ich]]; Rectangle rcT = new Rectangle(xT, 1, cx, cy); xT += cx; Bitmap bmT = new Bitmap(cx, cy, PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bmT); g.DrawImage(bm, 0, 0, rcT, GraphicsUnit.Pixel); g.Dispose(); // Compile scan data TBitmap tbm = new TBitmap(bmT, pal); bmT.Dispose(); // Save scan data serialization alsSdEven.Add(tbm.SerializeScanData()); } //FontHeader { // word cy; // byte acxChar[256]; // word mpchibsdEven[256]; // ScanData asd[1]; //}; // First serialize scan data ArrayList alsIbsdEven = new ArrayList(); ArrayList alsSd = new ArrayList(); foreach (byte[] absd in alsSdEven) { if ((alsSd.Count & 1) != 0) alsSd.Add((byte)0); alsIbsdEven.Add(alsSd.Count); alsSd.AddRange(absd); } // Write out to file BinaryWriter bwtr = new BinaryWriter(new FileStream(strFileSave, FileMode.Create, FileAccess.Write)); // Height bwtr.Write(Misc.SwapUShort((ushort)cy)); // Ascii ordered char widths in bytes. First init 0's to width of '?' if (ichDefault != -1) { for (ich = 0; ich < acxChar.Length; ich++) { if (acxChar[ich] == 0) { acxChar[ich] = acxChar[strAscii[ichDefault]]; } } } bwtr.Write(acxChar); // Ascii ordered offsets to even scan data (even) // Fill unused entries to entry for '?' int[] aibsdEven = new int[256]; for (int ibsd = 0; ibsd < aibsdEven.Length; ibsd++) aibsdEven[ibsd] = -1; for (int i = 0; i < cch; i++) aibsdEven[strAscii[i]] = (int)alsIbsdEven[i]; if (ichDefault != -1) { for (int ibsd = 0; ibsd < aibsdEven.Length; ibsd++) { if (aibsdEven[ibsd] == -1) { aibsdEven[ibsd] = (int)alsIbsdEven[ichDefault]; } } } // Write it out int cbHeader = 2 + 256 + 512; for (int i = 0; i < 256; i++) bwtr.Write(Misc.SwapUShort((ushort)(cbHeader + aibsdEven[i]))); // Now save scan data bwtr.Write((byte[])alsSd.ToArray(typeof(byte))); // Done bwtr.Close(); }
private void mniExport_Click(object sender, System.EventArgs e) { if (exportFileDialog.ShowDialog() != DialogResult.OK) return; string strExportDir = Path.GetDirectoryName(exportFileDialog.FileName); #if false if (m_strPaletteFileName == null) { if (openPaletteFileDialog.ShowDialog() != DialogResult.OK) return; m_strPaletteFileName = openPaletteFileDialog.FileName; m_pal = new Palette(m_strPaletteFileName); } #endif AED.Export(m_anis, strExportDir, m_pal, false, false); }
public static int Main(string[] astrArgs) { bool fGui, fLoad = false, fImport = false, fSaveAs = false, fExport = false; bool fCrunch = false, fPalette = false, fValidateColors = false; string strLoadFileName = null, strImportFileSpec = null, strSaveAsFileName = null, strExportPath = null; string strPaletteFileName = null; fGui = astrArgs.Length == 0; // Parse command line arguments. Commands can be in any order. for (int i = 0; i < astrArgs.Length; i++) { switch (astrArgs[i]) { case "-g": fGui = true; break; case "-p": fPalette = true; if (i + 1 >= astrArgs.Length) { Console.WriteLine("Error: -p command requires a filename argument"); return -1; } strPaletteFileName = astrArgs[++i]; break; case "-v": gfVerbose = true; break; case "-v2": gfVerbose = true; gfSuperVerbose = true; break; case "-validatecolors": fValidateColors = true; break; case "-c": fCrunch = true; break; case "-l": fLoad = true; if (i + 1 >= astrArgs.Length) { Console.WriteLine("Error: -f command requires a filename argument"); return -1; } strLoadFileName = astrArgs[++i]; break; case "-i": fImport = true; if (i + 1 >= astrArgs.Length) { Console.WriteLine("Error: -i command requires a filespec argument"); return -1; } strImportFileSpec = astrArgs[++i]; break; case "-s": fSaveAs = true; if (i + 1 < astrArgs.Length && !astrArgs[i + 1].StartsWith("-")) strSaveAsFileName = astrArgs[++i]; break; case "-x": fExport = true; if (i + 1 < astrArgs.Length && !astrArgs[i + 1].StartsWith("-")) strExportPath = astrArgs[++i]; break; case "-?": case "-help": case "/?": case "/help": Console.WriteLine( "Usage:\nAED [-v] [-c] [-p palette.pal] <-l <filename> | -i <filespec>> [-s [filename]] [-x [dir]]\n" + "-v: verbose\n" + "-v2: super verbose!\n" + "-c: crunch (compile to runtime format) when exporting\n" + "-p palette.pal: specify the palette to be matched to when crunching to 8-bpp\n" + "-l filename: load a .ani animation\n" + "-s filename: save a .ani animation\n" + "-i filespec: import a set of bitmaps\n" + "-x dir: export a set of bitmaps to the specified directory\n" + "-validatecolors: during crunch, validate that all pixel colors are in\n" + " the specified palette\n"); return 0; default: Console.WriteLine("Error: Unknown command line argument \"{0}\"", astrArgs[i]); return -1; } } // Additional command validation if (fLoad && fImport) { Console.WriteLine("Error: Can't use -l and -i commands together, they're ambiguous"); return -1; } if (!fGui && !fLoad && !fImport) { Console.WriteLine("Error: Must specify either -l or -i command so AED has something to work with"); return -1; } // Execute the specified commands AnimSet anis = new AnimSet(); if (fLoad) { if (gfVerbose) Console.WriteLine("Loading {0}...", strLoadFileName); if (!Load(anis, strLoadFileName)) return -1; } if (fImport) { if (gfVerbose) Console.WriteLine("Importing {0}...", strImportFileSpec); if (!Import(anis, strImportFileSpec)) return -1; } if (fGui) { // This is modal and won't return until the MainForm is closed Application.Run(new Gui(anis.Items.Count != 0 ? anis : null)); } if (fSaveAs) { if (gfVerbose) Console.WriteLine("Saving {0}...", strSaveAsFileName); if (!SaveAs(anis, strSaveAsFileName)) return -1; } if (fExport) { if (gfVerbose) Console.WriteLine("Exporting {1} to {0}...", strExportPath, anis.Name); Palette pal = null; if (fPalette) pal = new Palette(strPaletteFileName); if (!Export(anis, strExportPath, pal, fCrunch, fValidateColors)) return -1; } return 0; }
public void SetPalette(Palette pal, bool fColorMatch) { m_pal = pal; SetModified(true); if (!fColorMatch) return; ArrayList alsColors = new ArrayList(); foreach (Template tmpl in m_alsTemplates) { Bitmap bm = tmpl.Bitmap; bool[,] afOccupancy = tmpl.OccupancyMap; int ctx = afOccupancy.GetLength(1); int cty = afOccupancy.GetLength(0); for (int ty = 0; ty < cty; ty++) { for (int tx = 0; tx < ctx; tx++) { if (!afOccupancy[ty, tx]) continue; int xOrigin = tx * m_sizTile.Width; int yOrigin = ty * m_sizTile.Height; for (int y = yOrigin; y < yOrigin + m_sizTile.Height; y++) { for (int x = xOrigin; x < xOrigin + m_sizTile.Width; x++) { Color clrOld = bm.GetPixel(x, y); Color clrNew = pal[pal.FindClosestEntry(clrOld)]; bm.SetPixel(x, y, clrNew); } } } } TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.OnTemplateChanged(this, "Bitmap", tmpl.Name, null); } }
void WriteMiniTiles(BinaryWriter bwtr, Palette pal, TemplateDoc tmpd, int cx, bool fNext, double nAreaBackgroundThreshold, double nLuminanceMultBackground, double nSaturationMultBackground, double nLuminanceMultForeground, double nSaturationMultForeground) { // struct MiniTileSetHeader { // mtshdr // ushort offNext; // ushort cTiles; // ushort cxTile; // ushort cyTile; // }; ushort offNext = 0; if (fNext) offNext = (ushort)(8 + m_alsTileData.Count * cx * cx); bwtr.Write(Misc.SwapUShort(offNext)); bwtr.Write(Misc.SwapUShort((ushort)m_alsTileData.Count)); bwtr.Write(Misc.SwapUShort((ushort)cx)); bwtr.Write(Misc.SwapUShort((ushort)cx)); // If a background template exists, use it to distinguish foreground from background objects for better minimaps Size sizTile = tmpd.TileSize; ArrayList alsColors = new ArrayList(); Template tmplBackground = tmpd.GetBackgroundTemplate(); if (tmplBackground != null && nAreaBackgroundThreshold >= 0.0) { // Get despeckled hue map of background, calc mean and // std dev for filtering purposes Bitmap bmHueBackground = TemplateTools.MakeHueMap(tmplBackground.Bitmap); TemplateTools.DespeckleGrayscaleBitmap(bmHueBackground, 9, 50); double nMean = TemplateTools.CalcGrayscaleMean(bmHueBackground); double nStdDev = TemplateTools.CalcGrayscaleStandardDeviation(bmHueBackground, nMean); // Go through each tile, first make a mask that'll delineate foreground from background Bitmap bmTile = new Bitmap(sizTile.Width, sizTile.Height); foreach (TileData td in m_alsTileData) { // Need to turn data back into a bitmap - doh! for (int y = 0; y < sizTile.Height; y++) { for (int x = 0; x < sizTile.Width; x++) { Color clr = (Color)td.aclr[y * sizTile.Width + x]; bmTile.SetPixel(x, y, clr); } } // Create mask which'll replace background with transparent color (255, 0, 255) Bitmap bmMask = TemplateTools.MakeHueMap(bmTile); TemplateTools.DespeckleGrayscaleBitmap(bmMask, 9, 50); TemplateTools.SubtractGrayscaleDistribution(bmMask, nMean, nStdDev); // Now scale tile down to desired size, using mask as input Bitmap bmScaled = TemplateTools.ScaleTemplateBitmap(bmTile, bmMask, cx, cx, nAreaBackgroundThreshold, nLuminanceMultBackground, nSaturationMultBackground, nLuminanceMultForeground, nSaturationMultForeground); // Grab the data for (int y = 0; y < cx; y++) { for (int x = 0; x < cx; x++) { alsColors.Add(bmScaled.GetPixel(x, y)); } } bmScaled.Dispose(); bmMask.Dispose(); } } else { // No background template; just scale Bitmap bmTile = new Bitmap(sizTile.Width, sizTile.Height); foreach (TileData td in m_alsTileData) { // Need to turn data back into a bitmap - doh! for (int y = 0; y < sizTile.Height; y++) { for (int x = 0; x < sizTile.Width; x++) { Color clr = (Color)td.aclr[y * sizTile.Width + x]; bmTile.SetPixel(x, y, clr); } } // Now scale tile down to desired size, using mask as input Bitmap bmScaled = TemplateTools.ScaleTemplateBitmap(bmTile, null, cx, cx, 1.0, 1.0, 1.0, 1.0, 1.0); // Grab the data for (int y = 0; y < cx; y++) { for (int x = 0; x < cx; x++) { alsColors.Add(bmScaled.GetPixel(x, y)); } } bmScaled.Dispose(); } } // Palette match and write results foreach (Color clr in alsColors) bwtr.Write((byte)pal.FindClosestEntry(clr)); }
public TileSet(TemplateDoc tmpd, string strFile, string strFilePal, int nDepth, Size sizTile) { TemplateDoc = tmpd; m_pal = new Palette(strFilePal + "_" + nDepth.ToString() + "bpp.pal"); TileCollectionFileName = strFile; FileName = strFile.Replace(".tc", ".tset"); PalBinFileName = Path.GetFileName(strFilePal) + ".palbin"; m_sizTile = sizTile; SuckTemplates(); }
public TileSet(TemplateDoc tmpd, string strFile) { TemplateDoc = tmpd; m_pal = tmpd.GetPalette(); m_sizTile = tmpd.TileSize; FileName = strFile.Replace(".tc", ".tset"); SuckTemplates(); }
/// <summary> /// /// </summary> /// <param name="bm"></param> /// <param name="pal"></param> public TBitmap(Bitmap bm, Palette pal) { m_bm = new Bitmap(bm); m_pal = pal; }
/// <summary> /// /// </summary> /// <param name="strFile"></param> /// <param name="pal"></param> public TBitmap(string strFile, Palette pal) { m_bm = new Bitmap(strFile); m_pal = pal; }
public TBitmap(Palette pal) { m_pal = pal; }
public TemplateDoc(SerializationInfo info, StreamingContext ctx) : base((DocTemplate)(((Hashtable)ctx.Context)["DocTemplate"]), (string)(((Hashtable)ctx.Context)["Filename"])) { m_cookie = info.GetInt32("Cookie"); // Backwards compat try { m_strNameBackground = info.GetInt32("CookieBackground").ToString(); } catch { m_strNameBackground = "0"; try { m_strNameBackground = info.GetString("NameBackground"); } catch { } } // Get tile size. If none, default 16,16 try { m_sizTile = (Size)info.GetValue("TileSize", typeof(Size)); } catch { m_sizTile = new Size(16, 16); } // Get palette try { m_pal = (Palette)info.GetValue("Palette", typeof(Palette)); } catch { m_pal = null; } m_alsTemplates = (ArrayList)info.GetValue("TileTemplates", typeof(ArrayList)); }
public static void MakePalette(string[] astr) { // -makepal 16 templates.tc palsize fixpalsize backgroundpalsize fixed.pal out.pal // tile size Size sizTile = new Size(0, 0); sizTile.Width = int.Parse(astr[1]); sizTile.Height = sizTile.Width; // Load template collection TemplateDoc tmpd = (TemplateDoc)DocManager.OpenDocument(astr[2]); // palette size int cPalEntries = int.Parse(astr[3]); // entries fixed int cPalEntriesFixed = int.Parse(astr[4]); // entries for background int cPalEntriesBackground = int.Parse(astr[5]); // fixed palette Palette palFixed = new Palette(astr[6]); // output palette string strFilePalOut = astr[7]; // If this template collection already has a palette it has already been quantized; we don't // want that. if (tmpd.GetPalette() != null) new Exception("Template collection has already been quantized!"); // Scale templates if needed if (sizTile.Width != tmpd.TileSize.Width || sizTile.Height != tmpd.TileSize.Height) TemplateTools.ScaleTemplates(tmpd, sizTile); // Quantize TemplateTools.QuantizeTemplates(tmpd, palFixed, cPalEntries, cPalEntriesFixed, cPalEntriesBackground); // Save the new palette out Palette palNew = tmpd.GetPalette(); palNew.SaveJasc(strFilePalOut); }
public TBitmap(string strFile, Palette pal) { m_pal = pal; Init(new Bitmap(strFile)); }
// Write the .anir file and .bmps or .tbms, depending on fCrunch public static bool Export(AnimSet anis, string strExportPath, Palette pal, bool fCrunch, bool fValidateColors) { Color clrTransparent = Color.FromArgb(0xff, 0, 0xff); SolidBrush brTransparent = new SolidBrush(clrTransparent); if (strExportPath == null) strExportPath = "."; ASCIIEncoding enc = new ASCIIEncoding(); FileStream stm = new FileStream(strExportPath + @"\" + anis.Name + ".anir", FileMode.Create, FileAccess.Write); BinaryWriter stmw = new BinaryWriter(stm); // Count the number of FrameSets (aka Strips) ushort cstpd = 0; foreach (DictionaryEntry deAnimSet in anis.Items) { Anim ani = (Anim)deAnimSet.Value; cstpd += (ushort)ani.Items.Count; } // Write AnimationFileHeader.cstpd stmw.Write(Misc.SwapUShort(cstpd)); // Write array of offsets to StripDatas (AnimationFileHeader.aoffStpd) ushort offStpd = (ushort)(2 + (2 * cstpd)); byte ibm = 0; ArrayList albm = new ArrayList(); foreach (DictionaryEntry deAnimSet in anis.Items) { Anim ani = (Anim)deAnimSet.Value; foreach (DictionaryEntry deAnim in ani.Items) { FrameSet frms = (FrameSet)deAnim.Value; stmw.Write(Misc.SwapUShort(offStpd)); // Advance offset to where the next StripData will be offStpd += (ushort)((26+1+1+2) /* sizeof(StripData) - sizeof(FrameData) */ + ((1+1+1+1+1+1) /* sizeof(FrameData) */ * frms.Count)); } } // Write array of StripDatas foreach (DictionaryEntry deAnimSet in anis.Items) { Anim ani = (Anim)deAnimSet.Value; foreach (DictionaryEntry deAnim in ani.Items) { FrameSet frms = (FrameSet)deAnim.Value; // Write StripData.Name string strName = ani.Name + " " + frms.Name; byte[] abT = new byte[26]; enc.GetBytes(strName, 0, Math.Min(strName.Length, 25), abT, 0); abT[25] = 0; stmw.Write(abT); // Write StripData.cDelay stmw.Write((byte)0); // Write StripData.bfFlags stmw.Write((byte)0); // Write StripData.cfrmd ushort cfrmd = (ushort)frms.Count; stmw.Write(Misc.SwapUShort(cfrmd)); // Write array of FrameDatas foreach (Frame frm in frms) { // Write FrameData.ibm (the index of the Bitmap as it will be in the Bitmap array) stmw.Write((byte)ibm); ibm++; // Add the Frame's Bitmap for output Bitmap bm = frm.Bitmap; if (fCrunch) { albm.Add(bm); } else { // If not crunching then we need to go through some special work to preserve // the origin point. Since the origin point is determined by finding the center // of the imported bitmap we preserve it at export by creating a new bitmap // sized so that he origin will be in its center. // The '+2' at the end gives us a pixel of transparent space padding the left // and right sides of the bitmap. We don't require this for any particular // reason but it comes in handy. int cxNew = (Math.Max(frm.OriginX, bm.Width - frm.OriginX) * 2) + 2; // The '+2' at the end is to ensure a single blank scanline at the top // which Import relies on to determine the transparent color. int cyNew = (Math.Max(frm.OriginY, bm.Height - frm.OriginY) * 2) + 2; using (Bitmap bmNew = new Bitmap(cxNew, cyNew, bm.PixelFormat)) { using (Graphics g = Graphics.FromImage(bmNew)) { g.FillRectangle(brTransparent, 0, 0, cxNew, cyNew); g.DrawImage(bm, cxNew / 2 - frm.OriginX, cyNew / 2 - frm.OriginY); } strName = anis.Name + "_" + ani.Name + "_" + frms.Name + "_" + frm.Index.ToString(); bmNew.Save(strExportPath + @"\" + strName + ".png", ImageFormat.Png); } } // Write FrameData.xOrigin, FrameData.yOrigin stmw.Write((byte)frm.OriginX); stmw.Write((byte)frm.OriginY); // Write FrameData.bCustomData1, FrameData.bCustomData2, FrameData.bCustomData3 stmw.Write((byte)0); stmw.Write((byte)0); stmw.Write((byte)0); } } } stmw.Close(); // Write out .tbm if (albm.Count != 0) { string strFileName = strExportPath + @"\" + anis.Name + ".tbm"; if (gfSuperVerbose) Console.WriteLine("Crunching and writing " + strFileName); TBitmap.Save((Bitmap[])albm.ToArray(typeof(Bitmap)), pal, strFileName); } return true; }
static Strip MakeHighlightStrip(AnimDoc doc, int cxTile, Palette palFixed) { Strip stpHelp = doc.StripSet["help"]; if (stpHelp == null) { return null; } // This does a deep copy Strip stpHighlight = (Strip)stpHelp.Clone(); stpHighlight.Name = "highlight"; // Figure out the scaling. It would be better to pass this in as // a parameter. Frame frT = stpHighlight[0]; Rectangle rcUnion = new Rectangle(); foreach (BitmapPlacer plc in frT.BitmapPlacers) { Rectangle rc = new Rectangle(); rc.X = -plc.X; rc.Y = -plc.Y; rc.Width = plc.XBitmap.Width; rc.Height = plc.XBitmap.Height; if (rcUnion.IsEmpty) { rcUnion = rc; } else { rcUnion = Rectangle.Union(rcUnion, rc); } } // Needs to be 4 tiles high. Keep aspect ratio int cy = rcUnion.Height; if (cy < cxTile * 4) { cy = cxTile * 4; } double nScale = 1.0; if (cy > rcUnion.Height) { nScale = (double)cy / (double)rcUnion.Height; } // Scale if (nScale != 1.0) { foreach (Frame fr in stpHighlight) { foreach (BitmapPlacer plc in fr.BitmapPlacers) { plc.XBitmap.Bitmap = TBitmapTools.ScaleBitmap( plc.XBitmap.Bitmap, nScale, palFixed); plc.X = (int)Math.Round(plc.X * nScale); plc.Y = (int)Math.Round(plc.Y * nScale); } Point pt = new Point(); pt.X = (int)Math.Round(fr.SpecialPoint.X * nScale); pt.Y = (int)Math.Round(fr.SpecialPoint.Y * nScale); fr.SpecialPoint = pt; } } return stpHighlight; }
public static void Save(Bitmap[] abm, Palette pal, string strFile) { // Open file for writing BinaryWriter bwtr = new BinaryWriter(new FileStream(strFile, FileMode.Create, FileAccess.Write)); // Convert into tbm's TBitmap[] atbm = new TBitmap[abm.Length]; for (int ibm = 0; ibm < abm.Length; ibm++) atbm[ibm] = new TBitmap(abm[ibm], pal); // Serialize the whole thing bwtr.Write(Serialize(atbm)); // All done bwtr.Close(); }
static void Scale(AnimDoc doc, double nScale, Palette palFixed, bool fScaleIcon) { if (nScale >= 1.5) doc.Hires = true; // If not scaling icon, make a clone of it so it doesn't get scaled, // then after scaling set this clone back in. Strip stpIcon = doc.StripSet["icon"]; Strip stpIconClone = null; if (!fScaleIcon && stpIcon != null) { stpIconClone = (Strip)stpIcon.Clone(); } // Scale all the bitmaps foreach (XBitmap xbm in doc.XBitmapSet) { // Scale xbm.Bitmap = TBitmapTools.ScaleBitmap(xbm.Bitmap, nScale, palFixed); // Scale the points in the frames that use this bitmap foreach (Strip stp in doc.StripSet) { foreach (Frame fr in stp) { foreach (BitmapPlacer plc in fr.BitmapPlacers) { if (plc.XBitmap == xbm) { plc.X = (int)Math.Round(plc.X * nScale); plc.Y = (int)Math.Round(plc.Y * nScale); } } } } } // Scale all special points too foreach (Strip stp in doc.StripSet) { foreach (Frame fr in stp) { Point pt = new Point(); pt.X = (int)Math.Round(fr.SpecialPoint.X * nScale); pt.Y = (int)Math.Round(fr.SpecialPoint.Y * nScale); fr.SpecialPoint = pt; } } // Put the strip icon back in if it shouldn't be scaled if (!fScaleIcon && stpIconClone != null) { // Patch in the clone and add the images to the XBitmapSet // (they are not added auto-magically). doc.StripSet[doc.StripSet.IndexOf(stpIcon)] = stpIconClone; foreach (Frame fr in stpIconClone) { foreach (BitmapPlacer plc in fr.BitmapPlacers) { doc.XBitmapSet.Add(plc.XBitmap); } } } }
static int Main(string[] astrArgs) { if (astrArgs.Length < 3 || astrArgs.Length > 10) { Console.WriteLine("Usage:\nacrunch [-scale N] [-save] [-noscaleicon] [-noshrinkwrap] [-highlight <cxTile>] [-stats] <palette.pal> <input.amx> <outdir>\n"); return -1; } double nScale = 1.0; bool fSave = false; bool fNoShrinkWrap = false; bool fDumpStats = false; bool fScaleIcon = true; bool fMakeHighlight = true; int cxTile = 0; int iarg = 0; while (astrArgs[iarg][0] == '-') { switch (astrArgs[iarg]) { case "-scale": nScale = double.Parse(astrArgs[++iarg]); break; case "-noscaleicon": fScaleIcon = false; break; case "-save": fSave = true; break; case "-noshrinkwrap": fNoShrinkWrap = true; break; case "-stats": fDumpStats = true; break; case "-highlight": fMakeHighlight = true; cxTile = Int32.Parse(astrArgs[++iarg]); break; } iarg++; } // Read in the palette string strFilePal = astrArgs[iarg++]; Palette pal = new Palette(strFilePal); if (pal == null) { Console.WriteLine("Error: unable to read the palette file {0}\n", strFilePal); return -1; } // Read in the animation file (.amx) string strFileAmx = astrArgs[iarg++]; AnimDoc doc = AnimDoc.Load(strFileAmx); if (doc == null) { Console.WriteLine("Error: unable to read animation file {0}\n", strFileAmx); return -1; } // Get directory string strDir = astrArgs[iarg++]; // Reduce the Bitmaps down to the tightest rectangular boundary around the // non-transparent pixels. if (!fNoShrinkWrap) ShrinkWrap(doc); // Make highlight if asked. This uses existing images, so do this // before scaling. Strip stpHighlight = null; if (fMakeHighlight) { stpHighlight = MakeHighlightStrip(doc, cxTile, pal); } // Scale if asked if (nScale != 1.0) { Scale(doc, nScale, pal, fScaleIcon); } // Add in highlight strip if (stpHighlight != null) { doc.StripSet.Add(stpHighlight); foreach (Frame fr in stpHighlight) { foreach (BitmapPlacer plc in fr.BitmapPlacers) { doc.XBitmapSet.Add(plc.XBitmap); } } } // If dump stats, we're *only* dumping stats if (fDumpStats) { DumpStats(doc); return 0; } // Write the runtime animation file (.anir) and crunched bitmaps if (fSave) doc.Save(strDir + Path.DirectorySeparatorChar + Path.GetFileName(strFileAmx)); else doc.WriteAnir(pal, strDir, Path.GetFileNameWithoutExtension(strFileAmx)); return 0; }
static Palette QuantizeColors(ArrayList alsColors, Palette palFixed, int cPalEntries, int cPalEntriesFixed) { Palette palNew = null; while (true) { palNew = QuantizeColors2(alsColors, palFixed, cPalEntries, cPalEntriesFixed); ArrayList alsColorsNew = new ArrayList(); foreach (Color clr in alsColors) { int iclr = palNew.FindClosestEntry(clr); if (iclr >= cPalEntriesFixed) alsColorsNew.Add(clr); } if (alsColorsNew.Count == alsColors.Count) break; alsColors = alsColorsNew; } return palNew; }
static unsafe int Main(string[] astrArgs) { // Command-line argument processing if (astrArgs.Length == 0) { PrintHelp(); return 0; } for (int i = 0; i < astrArgs.Length; i++) { switch (astrArgs[i]) { case "-?": PrintHelp(); return 0; case "-i": giclrInsert = Int32.Parse(astrArgs[++i]); break; case "-p": gcPaletteEntries = Int32.Parse(astrArgs[++i]); break; case "-c": gcColorEntries = Int32.Parse(astrArgs[++i]); break; case "-t": gfEliminateTransparentColor = true; break; case "-s": gfEliminateShadowColor = true; break; case "-v": gfVerbose = true; break; case "-u": gfPrintColorUsers = true; break; case "-6": gf6bitRGB = true; break; case "-h": gfPrintHistogram = true; break; case "-a": gfAnalyse = true; break; case "-n": gfPhotoshopPad = true; break; case "-f": AddFilesFromFile(astrArgs[++i]); break; case "-o": if (i + 1 >= astrArgs.Length) { Console.WriteLine("Error: -o command requires a filename argument"); return -1; } gstrOutputFileName = astrArgs[++i]; break; default: if (astrArgs[i][0] == '-') { Console.WriteLine("Error: invalid flag '{0}'", astrArgs[i]); return -1; } // Assume all 'unassociated' arguments are input filenames (potentially wildcarded) AddFiles(astrArgs[i]); break; } } if (gstrcFileNames.Count == 0) { Console.WriteLine("Error: no files specified"); return -1; } // Build a list of the colors used and count of uses for each bitmap ArrayList alstBitmapColorInfos = new ArrayList(); foreach (string strFileName in gstrcFileNames) { BitmapColorInfo bci = new BitmapColorInfo(); bci.strFileName = strFileName; bci.htColorCount = new Hashtable(); // Handle .PALs if (strFileName.ToLower().EndsWith(".pal")) { Palette pal = new Palette(strFileName); int i = 0; foreach (Color clr in pal.Colors) { Color clrT = clr; if (gf6bitRGB) clrT = Color.FromArgb(clr.R & 0xfc, clr.G & 0xfc, clr.B & 0xfc); // This hack causes the .PAL colors to be sorted at the head of the // combined palette while retaining the order they were found in the .PAL. if (!bci.htColorCount.Contains(clrT)) bci.htColorCount[clrT] = (Int32.MaxValue / 2) - i++; } // Handle everything else (bitmaps) } else { Bitmap bm = null; try { bm = new Bitmap(strFileName); } catch { Console.WriteLine("Error: {0} is not a recognized bitmap or palette file", strFileName); continue; } // Prep to filter out the transparent color Color clrTransparent = Color.GhostWhite; if (gfEliminateTransparentColor) clrTransparent = bm.GetPixel(0, 0); // Prep to filter out the shadow color Color clrShadow = Color.GhostWhite; if (gfEliminateShadowColor) clrShadow = Color.FromArgb(156, 212, 248); // Keep a per-bitmap list of unique colors and how many times they're used Hashtable ht = bci.htColorCount; // Lock down bits for speed Rectangle rc = new Rectangle(0, 0, bm.Width, bm.Height); BitmapData bmd = bm.LockBits(rc, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); byte *pbBase = (byte *)bmd.Scan0.ToPointer(); for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { byte *pb = pbBase + y * bmd.Stride + x * 3; Color clr = Color.FromArgb(pb[2], pb[1], pb[0]); if (gfEliminateTransparentColor && clr == clrTransparent) continue; if (gfEliminateShadowColor && clr == clrShadow) continue; if (gf6bitRGB) clr = Color.FromArgb(clr.R & 0xfc, clr.G & 0xfc, clr.B & 0xfc); object obT = ht[clr]; if (obT == null) ht[clr] = 1; else ht[clr] = 1 + (int)obT; } } bm.UnlockBits(bmd); } if (gfVerbose) Console.WriteLine("{0} uses {1} colors", strFileName, bci.htColorCount.Count); if (gfPrintHistogram && gfVerbose) { foreach (DictionaryEntry de in bci.htColorCount) { Color clr = (Color)de.Key; Console.WriteLine("{0},{1},{2} : {3} occurances", clr.R, clr.G, clr.B, (int)de.Value); } Console.WriteLine(); } alstBitmapColorInfos.Add(bci); } if (alstBitmapColorInfos.Count == 0) { Console.WriteLine("Error: no valid bitmap files to process, terminating"); return -1; } // Combine all the color tables and count data Hashtable htCombined = new Hashtable(); foreach (BitmapColorInfo bci in alstBitmapColorInfos) { foreach (DictionaryEntry de in bci.htColorCount) { Color clr = (Color)de.Key; ColorCounter clrc = (ColorCounter)htCombined[clr]; if (clrc == null) { clrc = new ColorCounter(); clrc.cclr = (int)de.Value; htCombined[clr] = clrc; } else { int nAdd = (int)de.Value; if (nAdd > Int32.MaxValue / 3) clrc.cclr = (int)de.Value; else if (clrc.cclr < Int32.MaxValue / 3) clrc.cclr += nAdd; } clrc.alBitmaps.Add(bci.strFileName); } } int cclrCombined = htCombined.Count; Console.WriteLine("Combined palette has {0} unique colors", cclrCombined); // Sort everything by # colors used ColorCounter[] aclrcSorted = new ColorCounter[cclrCombined]; // int i = 0; // foreach (ColorCounter clrc in htCombined.Values) // acOccurancesSorted[i++] = clrc.cclr; htCombined.Values.CopyTo(aclrcSorted, 0); Color[] aclrSorted = new Color[cclrCombined]; htCombined.Keys.CopyTo(aclrSorted, 0); Array.Sort(aclrcSorted, aclrSorted); // Reverse so most-used colors come first // OPT: could do this inside the Sort above by specifying a custom IComparer Array.Reverse(aclrcSorted); Array.Reverse(aclrSorted); if (gfPrintHistogram || gfPrintColorUsers) { for (int i = 0; i < cclrCombined; i++) { Color clr = aclrSorted[i]; int cOccurances = aclrcSorted[i].cclr; if (cOccurances >= Int32.MaxValue / 3) Console.WriteLine("{0},{1},{2} : preloaded", clr.R, clr.G, clr.B); else Console.WriteLine("{0},{1},{2} : {3} occurances", clr.R, clr.G, clr.B, cOccurances); if (gfPrintColorUsers) { foreach (string strFileName in aclrcSorted[i].alBitmaps) { Console.WriteLine(" {0}", strFileName); } } } } // Print warning if # of unique colors is greater than the desired palette size // Truncate to match the requested size since other tools depend on this if (cclrCombined > gcColorEntries) { Console.WriteLine("Warning! {0} unique colors, {1} palette entries reserved. Truncating...", cclrCombined, gcColorEntries); Color[] aclrSortedT = new Color[gcColorEntries]; Array.Copy(aclrSorted, 0, aclrSortedT, 0, gcColorEntries); aclrSorted = aclrSortedT; ColorCounter[] aclrcSortedT = new ColorCounter[gcColorEntries]; Array.Copy(aclrcSorted, 0, aclrcSortedT, 0, gcColorEntries); aclrcSorted = aclrcSortedT; cclrCombined = gcColorEntries; } // Create the palette. Presorted colors start at 0. New colors start at giclrInsert. // giclrInsert == -1 means new colors are simply appended to the presorted colors. Color[] aclrPalette = aclrSorted; if (giclrInsert != -1) { // Init to transparent aclrPalette = new Color[gcColorEntries]; for (int i = 0; i < aclrPalette.Length; i++) aclrPalette[i] = Color.FromArgb(255, 0, 255); // Insert new colors appropriately int iclrBase = -1; for (int i = 0; i < cclrCombined; i++) { if (aclrcSorted[i].cclr >= Int32.MaxValue / 3) { aclrPalette[i] = aclrSorted[i]; continue; } if (iclrBase == -1) iclrBase = i; int iclrNew = giclrInsert + (i - iclrBase); if (iclrNew < aclrPalette.Length) aclrPalette[iclrNew] = aclrSorted[i]; } } // Write the output palette file, if requested if (gstrOutputFileName != null) { Palette pal = new Palette(aclrPalette); if (gfPhotoshopPad) pal.Pad(gcPaletteEntries, pal[pal.Length - 1]); else pal.Pad(gcPaletteEntries, Color.FromArgb(255, 0, 255)); pal.SaveJasc(gstrOutputFileName); } if (gfAnalyse) { Palette pal = new Palette(aclrPalette); // For each color find the nearest color in RGB space and print // the pair as well as the distance between them. for (int iclrA = 0; iclrA < aclrPalette.Length; iclrA++) { Color clrA = aclrPalette[iclrA]; // Find the entry, the long way int nLowest = 256 * 256 * 3; int iLowest = 0; for (int iclr = 0; iclr < aclrPalette.Length; iclr++) { if (iclr == iclrA) continue; Color clrPal = aclrPalette[iclr]; int dR = clrPal.R - clrA.R; int dG = clrPal.G - clrA.G; int dB = clrPal.B - clrA.B; int nD = dR * dR + dG * dG + dB * dB; if (nD < nLowest) { nLowest = nD; iLowest = iclr; } } Color clrB = aclrPalette[iLowest]; double n = Math.Sqrt(nLowest); Console.WriteLine("{8:#.##}\t[{3}] {0},{1},{2} \t[{7}] {4},{5},{6}", clrA.R, clrA.G, clrA.B, iclrA, clrB.R, clrB.G, clrB.B, iLowest, n); } } return 0; }
static unsafe int Main(string[] astrArgs) { // Command-line argument processing if (astrArgs.Length == 0) { PrintHelp(); return 0; } for (int i = 0; i < astrArgs.Length; i++) { switch (astrArgs[i]) { case "-?": PrintHelp(); return 0; case "-p": gstrPalette = astrArgs[++i]; gpal = new Palette(gstrPalette); break; case "-6": gf6bitRGB = true; break; default: if (astrArgs[i][0] == '-') { Console.WriteLine("Error: invalid flag '{0}'", astrArgs[i]); return -1; } // Assume all 'unassociated' arguments are input filenames (potentially wildcarded) string strDir = Path.GetDirectoryName(astrArgs[i]); if (strDir == "") strDir = "."; string[] astrFileNames = Directory.GetFiles(strDir, Path.GetFileName(astrArgs[i])); if (astrFileNames.Length == 0) { gstrcFileNames.Add(astrArgs[i]); } else { foreach (string strFileName in astrFileNames) { if (strFileName.ToLower().EndsWith(".ani")) { string strT = Path.GetDirectoryName(strFileName) + @"\" + Path.GetFileNameWithoutExtension(strFileName) + @"\*.png"; string[] astrT = Directory.GetFiles(Path.GetDirectoryName(strT), Path.GetFileName(strT)); gstrcFileNames.AddRange(astrT); } else { gstrcFileNames.Add(strFileName); } } } break; } } if (gpal == null) { Console.WriteLine("A valid palette must be specified via the '-p' switch"); return -1; } if (gstrcFileNames.Count == 0) { Console.WriteLine("Error: no files specified"); return -1; } int nReturnValue = 0; Color clrShadow = Color.FromArgb(156, 212, 248); Console.Write("Verifying bitmap colors..."); foreach (string strFileName in gstrcFileNames) { Hashtable htInvalidColors = new Hashtable(); Bitmap bm = null; try { bm = new Bitmap(strFileName); } catch { Console.WriteLine("Error: {0} is not a recognized bitmap or palette file", strFileName); continue; } Color clrTransparent = bm.GetPixel(0, 0); if (gf6bitRGB) clrTransparent = Color.FromArgb(clrTransparent.R & 0xfc, clrTransparent.G & 0xfc, clrTransparent.B & 0xfc); // Lock down bits for speed Rectangle rc = new Rectangle(0, 0, bm.Width, bm.Height); BitmapData bmd = bm.LockBits(rc, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); byte *pbBase = (byte *)bmd.Scan0.ToPointer(); for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { byte *pb = pbBase + y * bmd.Stride + x * 3; Color clr; if (gf6bitRGB) clr = Color.FromArgb(pb[2] & 0xfc, pb[1] & 0xfc, pb[0] & 0xfc); else clr = Color.FromArgb(pb[2], pb[1], pb[0]); int i = gpal.FindClosestEntry(clr); if (gpal[i] != clr && clr != clrShadow && clr != clrTransparent && !htInvalidColors.ContainsKey(clr)) htInvalidColors.Add(clr, clr); } } bm.UnlockBits(bmd); // Report any invalid colors if (htInvalidColors.Count != 0) { if (nReturnValue == 0) Console.WriteLine(); nReturnValue = -1; int cclr = htInvalidColors.Count; Color[] aclr = new Color[cclr]; htInvalidColors.Values.CopyTo(aclr, 0); Console.Write("{0} contains {1} invalid color{2} (", Path.GetFileName(strFileName), cclr, cclr == 1 ? "" : "s"); for (int i = 0; i < aclr.Length; i++) { Color clr = aclr[i]; Console.Write("{0},{1},{2}", clr.R, clr.G, clr.B); if (i != aclr.Length - 1) Console.Write(", "); } Console.WriteLine(")"); } } if (nReturnValue == 0) Console.WriteLine("done"); return nReturnValue; }
static public void SaveFont(string strFileBitmap, Palette pal, string strFileAscii, string strFileSave) { // Get the character order TextReader tr = new StreamReader(strFileAscii); string strAscii = tr.ReadLine(); tr.Close(); // Get the character count int cch = strAscii.Length; // Load the image, lose scaling factor Bitmap bmFile = new Bitmap(strFileBitmap); Bitmap bm = Misc.NormalizeBitmap(bmFile); bmFile.Dispose(); // Turn this on to see the character -> glyph mapping as it happens (help for // finding 'font bugs'). Set a breakpoint below on frm.Dispose(). #if SHOWFONT Form frm = new Form(); frm.Height = 1000; frm.Show(); Graphics gT = frm.CreateGraphics(); gT.InterpolationMode = InterpolationMode.NearestNeighbor; int yDst = 0; int xDst = 0; #endif // Scan the bitmap for widths int xLast = 0; int ich = 0; byte[] acxChar = new byte[256]; for (int x = 0; x < bm.Width; x++) { if (bm.GetPixel(x, 0) != Color.FromArgb(255, 0, 255)) { Debug.Assert(ich < cch); acxChar[strAscii[ich]] = (byte)(x - xLast); #if SHOWFONT gT.DrawString(strAscii[ich].ToString(), frm.Font, new SolidBrush(frm.ForeColor), new PointF(xDst, yDst)); Rectangle rcDst = new Rectangle(xDst + 20, yDst + 2, (x - xLast), bm.Height); Rectangle rcSrc = new Rectangle(xLast, 1, x - xLast, bm.Height); gT.DrawImage(bm, rcDst, rcSrc, GraphicsUnit.Pixel); yDst += Math.Max(bm.Height, frm.Font.Height); if (yDst > frm.ClientRectangle.Height) { xDst += 50; yDst = 0; } gT.Flush(); Application.DoEvents(); #endif ich++; xLast = x; } } #if SHOWFONT gT.Dispose(); frm.Dispose(); #endif if (ich != cch) { MessageBox.Show(String.Format("Expecting {0} characters but found {2}{1}.", cch, ich, ich < cch ? "only " : ""), "bcr2 - Font Compilation Error"); Debug.Assert(ich == cch - 1); } int cy = bm.Height - 1; // Save serialization ArrayList alsSdEven = new ArrayList(); int xT = 0; int ichDefault = -1; for (ich = 0; ich < cch; ich++) { // ? is the default "no glyph" character if (strAscii[ich] == '?') { ichDefault = ich; } // Get subimage int cx = acxChar[strAscii[ich]]; Rectangle rcT = new Rectangle(xT, 1, cx, cy); xT += cx; Bitmap bmT = new Bitmap(cx, cy, PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bmT); g.DrawImage(bm, 0, 0, rcT, GraphicsUnit.Pixel); g.Dispose(); // Compile scan data TBitmap tbm = new TBitmap(bmT, pal); bmT.Dispose(); // Save scan data serialization alsSdEven.Add(tbm.SerializeScanData()); } //FontHeader { // word cy; // byte acxChar[256]; // word mpchibsdEven[256]; // ScanData asd[1]; //}; // First serialize scan data ArrayList alsIbsdEven = new ArrayList(); ArrayList alsSd = new ArrayList(); foreach (byte[] absd in alsSdEven) { if ((alsSd.Count & 1) != 0) { alsSd.Add((byte)0); } alsIbsdEven.Add(alsSd.Count); alsSd.AddRange(absd); } // Write out to file BinaryWriter bwtr = new BinaryWriter(new FileStream(strFileSave, FileMode.Create, FileAccess.Write)); // Height bwtr.Write(Misc.SwapUShort((ushort)cy)); // Ascii ordered char widths in bytes. First init 0's to width of '?' if (ichDefault != -1) { for (ich = 0; ich < acxChar.Length; ich++) { if (acxChar[ich] == 0) { acxChar[ich] = acxChar[strAscii[ichDefault]]; } } } bwtr.Write(acxChar); // Ascii ordered offsets to even scan data (even) // Fill unused entries to entry for '?' int[] aibsdEven = new int[256]; for (int ibsd = 0; ibsd < aibsdEven.Length; ibsd++) { aibsdEven[ibsd] = -1; } for (int i = 0; i < cch; i++) { aibsdEven[strAscii[i]] = (int)alsIbsdEven[i]; } if (ichDefault != -1) { for (int ibsd = 0; ibsd < aibsdEven.Length; ibsd++) { if (aibsdEven[ibsd] == -1) { aibsdEven[ibsd] = (int)alsIbsdEven[ichDefault]; } } } // Write it out int cbHeader = 2 + 256 + 512; for (int i = 0; i < 256; i++) { bwtr.Write(Misc.SwapUShort((ushort)(cbHeader + aibsdEven[i]))); } // Now save scan data bwtr.Write((byte[])alsSd.ToArray(typeof(byte))); // Done bwtr.Close(); }