diff --git a/OpenRA.FileFormats/Graphics/PngLoader.cs b/OpenRA.FileFormats/Graphics/PngLoader.cs index bc51e0b69d..c51fc2cbc8 100644 --- a/OpenRA.FileFormats/Graphics/PngLoader.cs +++ b/OpenRA.FileFormats/Graphics/PngLoader.cs @@ -24,7 +24,8 @@ namespace OpenRA.FileFormats.Graphics { public static Bitmap Load(string filename) { - return Load(File.OpenRead(filename)); + using (var s = File.OpenRead(filename)) + return Load(s); } public static Bitmap Load(Stream s) diff --git a/OpenRA.FileFormats/Graphics/ShpReader.cs b/OpenRA.FileFormats/Graphics/ShpReader.cs index 3e99905c81..3ff3203224 100644 --- a/OpenRA.FileFormats/Graphics/ShpReader.cs +++ b/OpenRA.FileFormats/Graphics/ShpReader.cs @@ -174,5 +174,11 @@ namespace OpenRA.FileFormats { return GetEnumerator(); } + + public static ShpReader Load(string filename) + { + using (var s = File.OpenRead(filename)) + return new ShpReader(s); + } } } diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index dba249fef0..92ba03c9f1 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -15,6 +15,11 @@ using System.Windows.Forms; using ICSharpCode.SharpZipLib; using ICSharpCode.SharpZipLib.Zip; using OpenRA.GameRules; +using OpenRA.FileFormats.Graphics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using OpenRA.FileFormats; namespace OpenRA.Utility { @@ -145,5 +150,67 @@ namespace OpenRA.Utility public static void AuthenticateAndExtractZip(string[] args) { AuthenticateAndExecute("--extract-zip-inner", args); } public static void AuthenticateAndInstallRAPackages(string[] args) { AuthenticateAndExecute( "--install-ra-packages-inner", args ); } public static void AuthenticateAndInstallCncPackages(string[] args) { AuthenticateAndExecute( "--install-cnc-packages-inner", args ); } + + public static void ConvertPngToShp(string[] args) + { + var src = args[1]; + var dest = Path.ChangeExtension(src, ".shp"); + var width = int.Parse(args[2]); + + var srcImage = PngLoader.Load(src); + + if (srcImage.Width % width != 0) + throw new InvalidOperationException("Bogus width; not a whole number of frames"); + + using (var destStream = File.Create(dest)) + ShpWriter.Write(destStream, width, srcImage.Height, + srcImage.ToFrames(width)); + } + + static IEnumerable ToFrames(this Bitmap bitmap, int width) + { + for (var x = 0; x < bitmap.Width; x += width) + { + var data = bitmap.LockBits(new Rectangle(x, 0, width, bitmap.Height), ImageLockMode.ReadOnly, + PixelFormat.Format8bppIndexed); + + var bytes = new byte[width * bitmap.Height]; + for (var i = 0; i < bitmap.Height; i++) + Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + i * data.Stride), + bytes, i * width, width); + + bitmap.UnlockBits(data); + + yield return bytes; + } + } + + public static void ConvertShpToPng(string[] args) + { + var src = args[1]; + var dest = Path.ChangeExtension(src, ".png"); + + var srcImage = ShpReader.Load(src); + + using (var bitmap = new Bitmap(srcImage.ImageCount * srcImage.Width, srcImage.Height, PixelFormat.Format8bppIndexed)) + { + var x = 0; + + foreach (var frame in srcImage) + { + var data = bitmap.LockBits(new Rectangle(x, 0, srcImage.Width, srcImage.Height), ImageLockMode.WriteOnly, + PixelFormat.Format8bppIndexed); + + for (var i = 0; i < bitmap.Height; i++) + Marshal.Copy(frame.Image, i * srcImage.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), srcImage.Width); + + Marshal.Copy(frame.Image, 0, data.Scan0, frame.Image.Length); + x += srcImage.Width; + } + + bitmap.Save(dest); + } + } } } diff --git a/OpenRA.Utility/OpenRA.Utility.csproj b/OpenRA.Utility/OpenRA.Utility.csproj index fd026f6fac..ce1d15765f 100644 --- a/OpenRA.Utility/OpenRA.Utility.csproj +++ b/OpenRA.Utility/OpenRA.Utility.csproj @@ -36,6 +36,7 @@ 3.5 + 3.5 diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index 1de9795468..96073af394 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -44,6 +44,8 @@ namespace OpenRA.Utility { "--install-ra-packages", Command.AuthenticateAndInstallRAPackages }, { "--install-cnc-packages", Command.AuthenticateAndInstallCncPackages }, { "--extract-zip", Command.AuthenticateAndExtractZip }, + { "--shp", Command.ConvertPngToShp }, + { "--png", Command.ConvertShpToPng }, }; if (args.Length == 0) { PrintUsage(); return; } @@ -99,6 +101,8 @@ namespace OpenRA.Utility Console.WriteLine(" --install-ra-packages PATH Install required packages for RA from CD to PATH"); Console.WriteLine(" --install-cnc-packages PATH Install required packages for C&C from CD to PATH"); Console.WriteLine(" --settings-value SUPPORTDIR KEY Get value of KEY in SUPPORTDIR/settings.yaml"); + Console.WriteLine(" --shp PNGFILE FRAMEWIDTH Convert a PNG containing one or more frames to a SHP"); + Console.WriteLine(" --png SHPFILE Convert a SHP to a PNG containing all of its frames"); } static T WithDefault(T def, Func f)