📄 bitmapmanipulator.cs
字号:
/// <summary>BitmapManipulator class, provides some useful static functions which
/// operate on .NET <code>Bitmap</code> objects in useful ways.
///
/// Some of the useful features of this class incldue:
/// <ul>
/// <li><code>GetBitmapFromUri</code> which downloads a bitmap from a URL, providing
/// some useful error message elaboration logic to present users with a more meaningful
/// error message in the event of a failure.</li>
///
/// <li><code>ConvertBitmap</code> functions, which convert a bitmap from one format
/// to another, including optional quality and compression parameters for codecs like JPEG and
/// TIFF, respectively.</li>
///
/// <li><code>ScaleBitmap</code> and <code>ResizeBitmap</code>, for modifying the dimensions
/// of a bitmap (these are standard issue and boring, but nonetheless useful)</li>
///
/// <li><code>ThumbnailBitmap</code>, a very useful function that produces a thumbnail of an image
/// that fits within a given rectangle</li>
///
/// <li><code>OverlayBitmap</code>, a useful function that overlays one bitmap atop another
/// with a caller-defined alpha parameter. Great for putting watermarks or logos on pictures.</li>
///
/// <li>A few other standard-issue image manipulation functions</li>
/// </ul>
///
/// NOTE: This code includes support for GIF en/decoding, via the .NET Framework's
/// System.Drawing classes. However, in order to provide GIF functionality in your
/// application, you must license the LZW encoding scheme used in GIF files from Unisys.
/// As this is an opportunistic money-grab akin to SCO's, you are well advised to refuse
/// to do this, and instead favor PNG whenever possible.
///
/// For more information, see http://www.microsoft.com/DEVONLY/Unisys.htm
///
/// Current Version: 1.0.0
/// Revision History:
/// 1.0.0 - ajn - 9/1/2003 - First release
///
/// Copyright(C) 2003 Adam J. Nelson.
///
/// This code is hereby released for unlimited non-commercial and commercial use
///
/// The author makes no guarantee regarding the fitness of this code, and hereby disclaims
/// all liability for any damage incurred as a result of using this code.
/// </summary>
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Net;
namespace apocryph.BitmapManip
{
/// <summary>
/// Utility class with static methods that do various useful things
/// with bitmaps that require multiple GDI+ calls with .NET CLR
/// </summary>
public class BitmapManipulator {
//MIME types for the various image formats
private const String MIME_JPEG = "image/jpeg";
private const String MIME_PJPEG = "image/pjpeg";
private const String MIME_GIF = "image/gif";
private const String MIME_BMP = "image/bmp";
private const String MIME_TIFF = "image/tiff";
private const String MIME_PNG = "image/x-png";
public class BitmapManipException : Exception {
public BitmapManipException(String msg, Exception innerException) : base(msg, innerException) {
}
}
public enum ImageCornerEnum {
TopLeft,
TopRight,
BottomRight,
BottomLeft,
Center
};
public enum TiffCompressionEnum {
CCITT3,
CCITT4,
LZW,
RLE,
None,
Unspecified
};
public static String[] supportedMimeTypes = new String[] {
MIME_GIF,
MIME_JPEG,
MIME_PJPEG,
MIME_TIFF,
MIME_PNG,
MIME_BMP
};
/// <summary>Attempts to download a bitmap from a given URI, then loads the bitmap into
/// a <code>Bitmap</code> object and returns.
///
/// Obviously there are numerous failure cases for a function like this. For ease
/// of use, all errors will be reported in a catch-all <code>BitmapManipException</code>,
/// which provides a textual error message based on the exception that occurs. As usual,
/// the underlying exception is available in <code>InnerException</code> property.
///
/// Times out after 10 seconds waiting for a response from the server.</summary>
///
/// <param name="uri">String containing URI from which to retrieve image</param>
///
/// <returns>Bitmap object from URI. Shouldn't ever be null, as any error will be reported
/// in an exception.</returns>
public static Bitmap GetBitmapFromUri(String uri) {
//Convert String to URI
try {
Uri uriObj = new Uri(uri);
return GetBitmapFromUri(uriObj);
} catch (ArgumentNullException ex) {
throw new BitmapManipException("Parameter 'uri' is null", ex);
} catch (UriFormatException ex) {
throw new BitmapManipException(String.Format("Parameter 'uri' is malformed: {0}", ex.Message),
ex);
}
}
/// <summary>Attempts to download a bitmap from a given URI, then loads the bitmap into
/// a <code>Bitmap</code> object and returns.
///
/// Obviously there are numerous failure cases for a function like this. For ease
/// of use, all errors will be reported in a catch-all <code>BitmapManipException</code>,
/// which provides a textual error message based on the exception that occurs. As usual,
/// the underlying exception is available in <code>InnerException</code> property.
///
/// Times out after 10 seconds waiting for a response from the server.</summary>
///
/// <param name="uri"><code>Uri</code> object specifying the URI from which to retrieve image</param>
///
/// <returns>Bitmap object from URI. Shouldn't ever be null, as any error will be reported
/// in an exception.</returns>
public static Bitmap GetBitmapFromUri(Uri uri) {
return GetBitmapFromUri(uri, 10*1000);
}
/// <summary>Attempts to download a bitmap from a given URI, then loads the bitmap into
/// a <code>Bitmap</code> object and returns.
///
/// Obviously there are numerous failure cases for a function like this. For ease
/// of use, all errors will be reported in a catch-all <code>BitmapManipException</code>,
/// which provides a textual error message based on the exception that occurs. As usual,
/// the underlying exception is available in <code>InnerException</code> property.
/// </summary>
///
/// <param name="uri">String containing URI from which to retrieve image</param>
/// <param name="timeoutMs">Timeout (in milliseconds) to wait for response</param>
///
/// <returns>Bitmap object from URI. Shouldn't ever be null, as any error will be reported
/// in an exception.</returns>
public static Bitmap GetBitmapFromUri(String uri, int timeoutMs) {
//Convert String to URI
try {
Uri uriObj = new Uri(uri);
return GetBitmapFromUri(uriObj, timeoutMs);
} catch (ArgumentNullException ex) {
throw new BitmapManipException("Parameter 'uri' is null", ex);
} catch (UriFormatException ex) {
throw new BitmapManipException(String.Format("Parameter 'uri' is malformed: {0}", ex.Message),
ex);
}
}
/// <summary>Attempts to download a bitmap from a given URI, then loads the bitmap into
/// a <code>Bitmap</code> object and returns.
///
/// Obviously there are numerous failure cases for a function like this. For ease
/// of use, all errors will be reported in a catch-all <code>BitmapManipException</code>,
/// which provides a textual error message based on the exception that occurs. As usual,
/// the underlying exception is available in <code>InnerException</code> property.
/// </summary>
///
/// <param name="uri"><code>Uri</code> object specifying the URI from which to retrieve image</param>
/// <param name="timeoutMs">Timeout (in milliseconds) to wait for response</param>
///
/// <returns>Bitmap object from URI. Shouldn't ever be null, as any error will be reported
/// in an exception.</returns>
public static Bitmap GetBitmapFromUri(Uri uri, int timeoutMs) {
Bitmap downloadedImage = null;
//Create a web request object for the URI, retrieve the contents,
//then feed the results into a new Bitmap object. Note that we
//are particularly sensitive to timeouts, since this all must happen
//while the user waits
try {
WebRequest req = WebRequest.Create(uri);
req.Timeout = timeoutMs;
//The GetResponse call actually makes the request
WebResponse resp = req.GetResponse();
//Check the content type of the response to make sure it is
//one of the formats we support
if (Array.IndexOf(BitmapManipulator.supportedMimeTypes,
resp.ContentType) == -1) {
String contentType = resp.ContentType;
resp.Close();
throw new BitmapManipException(String.Format("The image at the URL you provided is in an unsupported format ({0}). Uploaded images must be in either JPEG, GIF, BMP, TIFF, PNG, or WMF formats.",
contentType),
new NotSupportedException(String.Format("MIME type '{0}' is not a recognized image type", contentType)));
}
//Otherwise, looks fine
downloadedImage = new Bitmap(resp.GetResponseStream());
resp.Close();
return downloadedImage;
} catch (UriFormatException exp) {
throw new BitmapManipException("The URL you entered is not valid. Please enter a valid URL, of the form http://servername.com/folder/image.gif",
exp);
} catch (WebException exp) {
//Some sort of problem w/ the web request
String errorDescription;
if (exp.Status == WebExceptionStatus.ConnectFailure) {
errorDescription = "Connect failure";
} else if (exp.Status == WebExceptionStatus.ConnectionClosed) {
errorDescription = "Connection closed prematurely";
} else if (exp.Status == WebExceptionStatus.KeepAliveFailure) {
errorDescription = "Connection closed in spite of keep-alives";
} else if (exp.Status == WebExceptionStatus.NameResolutionFailure) {
errorDescription = "Unable to resolve server name. Double-check the URL for errors";
} else if (exp.Status == WebExceptionStatus.ProtocolError) {
errorDescription = "Protocol-level error. The server may have reported an error like 404 (file not found) or 403 (access denied), or some other similar error";
} else if (exp.Status == WebExceptionStatus.ReceiveFailure) {
errorDescription = "The server did not send a complete response";
} else if (exp.Status == WebExceptionStatus.SendFailure) {
errorDescription = "The complete request could not be sent to the server";
} else if (exp.Status == WebExceptionStatus.ServerProtocolViolation) {
errorDescription = "The server response was not a valid HTTP response";
} else if (exp.Status == WebExceptionStatus.Timeout) {
errorDescription = "The server did not respond quickly enough. The server may be down or overloaded. Try again later";
} else {
errorDescription = exp.Status.ToString();
}
throw new BitmapManipException(String.Format("An error occurred while communicating with the server at the URL you provided. {0}.",
errorDescription),
exp);
} catch (BitmapManipException exp) {
//Don't modify this one; pass it along
throw exp;
} catch (Exception exp) {
throw new BitmapManipException(String.Format("An error ocurred while retrieving the image from the URL you provided: {0}",
exp.Message),
exp);
}
}
/// <summary>Converts a bitmap to a JPEG with a specific quality level</summary>
///
/// <param name="inputBmp">Bitmap to convert</param>
/// <param name="quality">Specifies a quality from 0 (lowest) to 100 (highest), or -1 to leave
/// unspecified</param>
///
/// <returns>A new bitmap object containing the input bitmap converted.
/// If the destination format and the target format are the same, returns
/// a clone of the destination bitmap.</returns>
public static Bitmap ConvertBitmapToJpeg(Bitmap inputBmp, int quality) {
//If the dest format matches the source format and quality not changing, just clone
if (inputBmp.RawFormat.Equals(ImageFormat.Jpeg) && quality == -1) {
return(Bitmap)inputBmp.Clone();
}
//Create an in-memory stream which will be used to save
//the converted image
System.IO.Stream imgStream = new System.IO.MemoryStream();
//Get the ImageCodecInfo for the desired target format
ImageCodecInfo destCodec = FindCodecForType(MimeTypeFromImageFormat(ImageFormat.Jpeg));
if (destCodec == null) {
//No codec available for that format
throw new ArgumentException("The requested format " +
MimeTypeFromImageFormat(ImageFormat.Jpeg) +
" does not have an available codec installed",
"destFormat");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -