using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; namespace RobvanderWoude { class RotateImage { static string progver = "1.02"; static int Main( string[] args ) { #region Parse Command Line if ( args.Length < 2 || args.Length > 4 ) { return ShowHelp( ); } string imagepath = String.Empty; string outputfile = String.Empty; string fileextout = String.Empty; int maxwidth = 0; int maxheight = 0; int rotateby = 90; foreach ( string arg in args ) { if ( arg[0] == '/' ) { if ( arg.Length > 3 && arg[2] == ':' ) { switch ( arg.ToUpper( )[1] ) { case 'M': if ( maxwidth != 0 ) { return ShowHelp( "Duplicate command line switch /M" ); } try { if ( arg.Substring( 3 ).ToLower( ).IndexOf( 'x' ) > 1 ) { maxwidth = Convert.ToInt32( arg.Substring( 3, arg.ToLower( ).IndexOf( 'x' ) - 3 ) ); maxheight = Convert.ToInt32( arg.Substring( arg.ToLower( ).IndexOf( 'x' ) + 1 ) ); } else { maxwidth = Convert.ToInt32( arg.Substring( 3 ) ); maxheight = maxwidth; } } catch { return ShowHelp( "size must be integer" ); } if ( maxwidth < 50 || maxwidth > 10000 ) { return ShowHelp( "size must be an integer between 50 and 10000" ); } break; case 'R': if ( rotateby != 90 ) { return ShowHelp( "Duplicate command line switch /R" ); } try { rotateby = Convert.ToInt32( arg.Substring( 3 ) ); } catch { return ShowHelp( "deg must be integer" ); } if ( ( rotateby % 90 ) != 0 ) { return ShowHelp( "deg must be a multiple of 90 degrees" ); } break; default: return ShowHelp( "Invalid command line argument: \"{0}\"", arg ); } } else { return ShowHelp( "Invalid command line argument: \"{0}\"", arg ); } } else { if ( String.IsNullOrEmpty( imagepath ) ) { imagepath = arg; if ( !File.Exists( imagepath ) ) { return ShowHelp( "Image file not found: \"{0}\"", imagepath ); } } else if ( String.IsNullOrEmpty( outputfile ) ) { outputfile = arg; if ( !Directory.Exists( Directory.GetParent( outputfile ).FullName ) ) { return ShowHelp( "Directory for output file not found: \"{0}\"", Directory.GetParent( outputfile ).FullName ); } fileextout = Path.GetExtension( outputfile ).ToLower( ); } else { return ShowHelp( "Invalid command line argument: \"{0}\"", arg ); } } } #endregion Parse Command Line #region Validate Command Line string fileextin = Path.GetExtension( imagepath ).ToLower( ); if ( String.IsNullOrEmpty( fileextout ) ) { fileextout = fileextin; } string filenamein = Path.GetFileNameWithoutExtension( imagepath ); string parentfolderin = Directory.GetParent( imagepath ).FullName; if ( String.IsNullOrEmpty( outputfile ) ) { outputfile = Path.Combine( parentfolderin, filenamein + "_rotated" + ( ( rotateby + 720 ) % 360 ).ToString( ) ); } ImageFormat formatout; switch ( fileextout ) { case ".bmp": formatout = ImageFormat.Bmp; break; case ".gif": formatout = ImageFormat.Gif; break; case ".jpg": case ".jpeg": formatout = ImageFormat.Jpeg; break; case ".png": formatout = ImageFormat.Png; break; case ".tif": case ".tiff": formatout = ImageFormat.Tiff; break; default: return -1; } #endregion Validate Command Line Bitmap bitmap = new Bitmap( imagepath ); int imagewidth = bitmap.Width; int imageheight = bitmap.Height; int rc = imagewidth; // Return code = image width before rotation if ( maxwidth > 0 ) { float aspectratio = (float) imagewidth / (float) imageheight; if ( imagewidth > maxwidth || imageheight > maxheight ) { float scale = Math.Min( (float) maxwidth / (float) imagewidth, (float) maxheight / (float) imageheight ); int newwidth = (int) ( (float) imagewidth * scale ); int newheight = (int) ( (float) imageheight * scale ); rc = newwidth; Bitmap resized = new Bitmap( newwidth, newheight ); // Return code = resized image width before rotation // Based on blog entry by DeltaWolf7 // http://www.deltasblog.co.uk/code-snippets/c-resizing-a-bitmap-image/ using ( Graphics graph = Graphics.FromImage( resized ) ) { graph.DrawImage( bitmap, 0, 0, newwidth, newheight ); } bitmap = resized; } } switch ( ( rotateby + 720 ) % 360 ) { case 90: bitmap.RotateFlip( RotateFlipType.Rotate90FlipNone ); break; case 180: bitmap.RotateFlip( RotateFlipType.Rotate180FlipNone ); break; case 270: bitmap.RotateFlip( RotateFlipType.Rotate270FlipNone ); break; default: // rotation 0 or invalid: do nothing break; } bitmap.Save( outputfile, formatout ); return rc; } #region Error handling public static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* RotateImage.exe, Version 1.02 Rotate a bitmap by a multiple of 90 degrees Usage: ROTATEIMAGE image [ output ] [ options ] Where: image input image file (bmp, gif, jpg, png or tif) output output file name and type (default: image_rotateddeg, same type as input image) Options: /M:size Maximum dimension of rotated image in pixels, either as (original) width x (original) height (e.g. /M:1024x768) or as a single number for the largest dimension (e.g. /M:1024, equivalent to /M:1024x1024); if image does not fit within the specified dimensions, it will be resized while preserving its original aspect ratio /R:deg Rotation in degrees (90, 180 or 270) Notes: Unless an output file name is specified, the rotated output file name is the input image file name with "_rotated" and the amount of degrees appended, e.g. image_rotated90.gif; if no output file is specified, the file types of input and output file are identical. Return code ("errorlevel") equals the width of the (resized) output image before rotation, or -1 in case of errors Written by Rob van der Woude http://www.robvanderwoude.com */ Console.Error.WriteLine( ); Console.Error.WriteLine( "RotateImage.exe, Version {0}", progver ); Console.Error.WriteLine( "Rotate a bitmap by a multiple of 90 degrees" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ROTATEIMAGE image [ output ] [ options ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "image" ); Console.ResetColor( ); Console.Error.WriteLine( " input image file (bmp, gif, jpg, png or tif)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " output" ); Console.ResetColor( ); Console.Error.Write( " output file name and type (default: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "image" ); Console.ResetColor( ); Console.Error.Write( "_rotated" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "deg" ); Console.ResetColor( ); Console.Error.WriteLine( ",)" ); Console.Error.WriteLine( " same type as input image)" ); Console.Error.WriteLine( ); Console.Error.Write( "Options: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/M:size M" ); Console.ResetColor( ); Console.Error.WriteLine( "aximum dimension of rotated image in pixels, either as" ); Console.Error.Write( " (original) " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "width x" ); Console.ResetColor( ); Console.Error.Write( " (original) " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "height" ); Console.ResetColor( ); Console.Error.Write( " (e.g. " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/M:1024x768" ); Console.ResetColor( ); Console.Error.WriteLine( ")" ); Console.Error.WriteLine( " or as a single number for the largest dimension (e.g." ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /M:1024" ); Console.ResetColor( ); Console.Error.Write( ", equivalent to " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/M:1024x1024" ); Console.ResetColor( ); Console.Error.WriteLine( "); if image does not" ); Console.Error.WriteLine( " fit within the specified dimensions, it will be resized" ); Console.Error.WriteLine( " while preserving its original aspect ratio" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /R:deg R" ); Console.ResetColor( ); Console.Error.Write( "otation in " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "deg" ); Console.ResetColor( ); Console.Error.WriteLine( "rees (90, 180 or 270; default: 0)" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Notes: Unless an output file name is specified, the rotated output file name" ); Console.Error.WriteLine( " is the input image file name with \"_rotated\" and the amount of degrees" ); Console.Error.Write( " appended, e.g. " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "image" ); Console.ResetColor( ); Console.Error.Write( "_rotated" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "90" ); Console.ResetColor( ); Console.Error.WriteLine( ".gif; if no output file is specified," ); Console.Error.WriteLine( " the file types of input and output file are identical." ); Console.Error.WriteLine( " Return code (\"errorlevel\") equals the width of the (resized) output" ); Console.Error.WriteLine( " image before rotation, or -1 in case of errors" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "http://www.robvanderwoude.com" ); #endregion Help Text return -1; } #endregion Error handling } }