using System; using System.Drawing; using System.Text.RegularExpressions; using System.IO; namespace AM { class AMImageResizer { public static bool ThumbnailCallback() { return false; } [STAThread] static int Main(string[] args) { if (args.Length < 1 || args.Length > 9 || args[0] == "/?" || args[0].ToLower() == "/help") { Console.Write("AMImageResizer version 1.0\n"+ "This program resizes an image and returns the resulting image size.\n\n"+ "Usage:\n"+ "AMImageResizer SourceFile [DestinationFile] [/Resize widthXheight]\n"+ "[/NoAutoAspect] [/Thumbnail] [/Size]\n\n" + "Example: AMImageResizer largeimage.jpg smallimage.jpg /Resize 640x480\n"+ "This would resize largeimage.jpg to smallimage.jpg with\n"+ "its width and height being proportional to source width and height\n"+ "and neither width exceeding 640 or height exceeding 480.\n\n"+ "If DestinationFile is not specified we save the resized image to\n"+ "SourceFile.\n\n"+ "If /Resize widthXheight is not specified we resize the image\n"+ "to its current size. You may want to use this to reduce an image's\n"+ "filesize. Both width and height do not need to be specified together.\n"+ "You could specify just /Resize x100 to make the height 100 and the width\n"+ "proportional to that. When both width and height are specified the\n"+ "original aspect ratio is maintained with the smaller of the width or\n"+ "height being the base measurement for SourceFiles whose proportions\n"+ "don't match the target width:height ratio (ex. 576x768 when resized\n"+ "to 100x75 will result in 56x75 size).\n\n"+ "If /NoAutoAspect is specified we will not automatically adjust\n"+ "the image dimensions. This switch may only be used if\n"+ "both width and height are specified.\n\n"+ "If /Thumbnail is specified the GetThumbnailImage method is used.\n"+ "This is recommended if you're resizing an image to a small\n"+ "size (100x75).\n\n"+ "If /Size is specified we will return the dimensions of SourceFile. We\n"+ "will not resize the image.\n\n\n"+ "Copyright 2003 by am.net - http://am.net - help@am.net\n"); return 0; } Image srcImage; Bitmap destImage; bool autoAspectRatio = true; bool useBitmap = true; bool returnDimensionsOnly = false; bool widthHeightSpecified = false; string srcFilename = ""; string destFilename = ""; double width = 0; double height = 0; for (int i = 0; i <= (args.Length-1); i++) { switch (args[i].ToLower()) { case "/resize": // if resize was specified and there is no argument after it // we break. this ensures we use the source width and height if (i == (args.Length-1)) { break; } Match dimensions = Regex.Match(args[i+1], "^(?[0-9]*)[Xx](?[0-9]*)$"); if (dimensions.Length == 0) { Console.Write("Error: Invalid parameter after /Resize"); return -1; } // if there was no match for width subexpression, // set width = 0; otherwise width equals the match width = (dimensions.Groups["width"].Length == 0) ? 0 : (int)Int32.Parse(dimensions.Groups["width"].Value); // if there was no match for the height subexpression, // set height = 0; otherwise height equals the match. height = (dimensions.Groups["height"].Length == 0) ? 0 : (int)Int32.Parse(dimensions.Groups["height"].Value); // Since the arguemnt after /Resize is the dimensions // which we've just parsed, we increment i so the next // iteration we will be on the argument after the dimensions. i++; widthHeightSpecified = true; break; case "/noautoaspect": if (width == 0 || height == 0) { Console.Write("Error: Both width and height must be specified "+ "to use /noAutoAspect"); return -1; } autoAspectRatio = false; break; case "/thumbnail": useBitmap = false; break; case "/size": returnDimensionsOnly = true; break; default: // if srcFilename has not been specified yet, this args // is srcFilename. otherwise if destFilename has not been // specified it's destFilename. if both have been specified // it's an illegal argument if (srcFilename.Length == 0) { srcFilename = args[i]; } else if (destFilename.Length == 0) { destFilename = args[i]; } else { Console.Write("Error: Illegal argument: " + args[i]); return -1; } break; } } if (destFilename == "") destFilename = srcFilename; try { srcImage = Image.FromFile(srcFilename); } catch { Console.Write("Error: Could not open " + args[0]); return -1; } if (returnDimensionsOnly) { Console.Write("{0}x{1}", srcImage.Width, srcImage.Height); return 0; } if (!widthHeightSpecified) { width = srcImage.Width; height = srcImage.Height; } else if (autoAspectRatio) { double widthRatio = srcImage.Width / width; double heightRatio = srcImage.Height / height; // If only one dimension was specified, scale the image based // on that dimension. if (width == 0) { width = srcImage.Width / heightRatio; } else if (height == 0) { height = srcImage.Height / widthRatio; } else { // We scale the image so that its dimensions are proportional // to the source--and neither scaled dimension is larger then the // specified dimensions. if (widthRatio > heightRatio) { height = srcImage.Height / widthRatio; } else { width = srcImage.Width / heightRatio; } } } try { if (!useBitmap) { Image.GetThumbnailImageAbort dummyCallBack = new Image.GetThumbnailImageAbort(ThumbnailCallback); destImage = (System.Drawing.Bitmap)srcImage.GetThumbnailImage( (int)width, (int)height, dummyCallBack, IntPtr.Zero); } else { destImage = new Bitmap(srcImage, (int)width, (int)height); } System.Drawing.Imaging.ImageFormat imageFormat = srcImage.RawFormat; srcImage.Dispose(); // We use to use Bitmap.Save to save the image but // on AM that wouldn't save the file "in-place". So instead // we use File.Create which seems to do this fine. //destImage.Save(destFilename, imageFormat); // we later discovered this kb article documenting the problem: // http://support.microsoft.com/default.aspx?scid=kb;en-us;312119 FileStream fr = File.Create(destFilename); destImage.Save(fr, imageFormat); fr.Flush(); fr.Close(); destImage.Dispose(); } catch (Exception e) { Console.Write("Error: Could not create destination image"); return -1; } Console.Write("{0}x{1}", (int)width, (int)height); return 0; } } }