📄 bitmapmanipulator.cs
字号:
//Create an EncoderParameters collection to contain the
//parameters that control the dest format's encoder
EncoderParameters destEncParams = new EncoderParameters(1);
//Use quality parameter
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
destEncParams.Param[0] = qualityParam;
//Save w/ the selected codec and encoder parameters
inputBmp.Save(imgStream, destCodec, destEncParams);
//At this point, imgStream contains the binary form of the
//bitmap in the target format. All that remains is to load it
//into a new bitmap object
Bitmap destBitmap = new Bitmap(imgStream);
//Free the stream
//imgStream.Close();
//For some reason, the above causes unhandled GDI+ exceptions
//when destBitmap.Save is called. Perhaps the bitmap object reads
//from the stream asynchronously?
return destBitmap;
}
/// <summary>Converts a bitmap to a Tiff with a specific compression</summary>
///
/// <param name="inputBmp">Bitmap to convert</param>
/// <param name="compression">The compression to use on the TIFF file output. Be warned that the CCITT3, CCITT4,
/// and RLE compression options are only applicable to TIFFs using a palette index color depth
/// (that is, 1, 4, or 8 bpp). Using any of these compression schemes with 24 or 32-bit
/// TIFFs will throw an exception from the bowels of GDI+</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 ConvertBitmapToTiff(Bitmap inputBmp, TiffCompressionEnum compression) {
//If the dest format matches the source format and quality/bpp not changing, just clone
if (inputBmp.RawFormat.Equals(ImageFormat.Tiff) && compression == TiffCompressionEnum.Unspecified) {
return(Bitmap)inputBmp.Clone();
}
if (compression == TiffCompressionEnum.Unspecified) {
//None of the params are chaning; use the general purpose converter
return ConvertBitmap(inputBmp, ImageFormat.Tiff);
}
//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.Tiff));
if (destCodec == null) {
//No codec available for that format
throw new ArgumentException("The requested format " +
MimeTypeFromImageFormat(ImageFormat.Tiff) +
" does not have an available codec installed",
"destFormat");
}
//Create an EncoderParameters collection to contain the
//parameters that control the dest format's encoder
EncoderParameters destEncParams = new EncoderParameters(1);
//set the compression parameter
EncoderValue compressionValue;
switch (compression) {
case TiffCompressionEnum.CCITT3:
compressionValue = EncoderValue.CompressionCCITT3;
break;
case TiffCompressionEnum.CCITT4:
compressionValue = EncoderValue.CompressionCCITT4;
break;
case TiffCompressionEnum.LZW:
compressionValue = EncoderValue.CompressionLZW;
break;
case TiffCompressionEnum.RLE:
compressionValue = EncoderValue.CompressionRle;
break;
default:
compressionValue = EncoderValue.CompressionNone;
break;
}
EncoderParameter compressionParam = new EncoderParameter(Encoder.Compression, (long)compressionValue);
destEncParams.Param[0] = compressionParam;
//Save w/ the selected codec and encoder parameters
inputBmp.Save(imgStream, destCodec, destEncParams);
//At this point, imgStream contains the binary form of the
//bitmap in the target format. All that remains is to load it
//into a new bitmap object
Bitmap destBitmap = new Bitmap(imgStream);
//Free the stream
//imgStream.Close();
//For some reason, the above causes unhandled GDI+ exceptions
//when destBitmap.Save is called. Perhaps the bitmap object reads
//from the stream asynchronously?
return destBitmap;
}
/// <summary>Converts a bitmap to another bitmap format, returning the new converted
/// bitmap
/// </summary>
///
/// <param name="inputBmp">Bitmap to convert</param>
/// <param name="destMimeType">MIME type of format to convert to</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 ConvertBitmap(Bitmap inputBmp, String destMimeType) {
return ConvertBitmap(inputBmp, ImageFormatFromMimeType(destMimeType));
}
/// <summary>Converts a bitmap to another bitmap format, returning the new converted
/// bitmap
/// </summary>
///
/// <param name="inputBmp">Bitmap to convert</param>
/// <param name="destFormat">Bitmap format to convert to</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 ConvertBitmap(Bitmap inputBmp, System.Drawing.Imaging.ImageFormat destFormat) {
//If the dest format matches the source format and quality/bpp not changing, just clone
if (inputBmp.RawFormat.Equals(destFormat)) {
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();
//Save the bitmap out to the memory stream, using the format indicated by the caller
inputBmp.Save(imgStream, destFormat);
//At this point, imgStream contains the binary form of the
//bitmap in the target format. All that remains is to load it
//into a new bitmap object
Bitmap destBitmap = new Bitmap(imgStream);
//Free the stream
//imgStream.Close();
//For some reason, the above causes unhandled GDI+ exceptions
//when destBitmap.Save is called. Perhaps the bitmap object reads
//from the stream asynchronously?
return destBitmap;
}
/// <summary>
/// Scales a bitmap by a scale factor, growing or shrinking both axes while
/// maintaining the original aspect ratio
/// </summary>
/// <param name="inputBmp">Bitmap to scale</param>
/// <param name="scaleFactor">Factor by which to scale</param>
/// <returns>New bitmap containing image from inputBmp, scaled by the scale factor</returns>
public static Bitmap ScaleBitmap(Bitmap inputBmp, double scaleFactor) {
return ScaleBitmap(inputBmp, scaleFactor, scaleFactor);
}
/// <summary>
/// Scales a bitmap by a scale factor, growing or shrinking both axes independently,
/// possibly changing the aspect ration
/// </summary>
/// <param name="inputBmp">Bitmap to scale</param>
/// <param name="scaleFactor">Factor by which to scale</param>
/// <returns>New bitmap containing image from inputBmp, scaled by the scale factor</returns>
public static Bitmap ScaleBitmap(Bitmap inputBmp, double xScaleFactor, double yScaleFactor) {
//Create a new bitmap object based on the input
Bitmap newBmp = new Bitmap(
(int)(inputBmp.Size.Width*xScaleFactor),
(int)(inputBmp.Size.Height*yScaleFactor),
PixelFormat.Format24bppRgb);//Graphics.FromImage doesn't like Indexed pixel format
//Create a graphics object attached to the new bitmap
Graphics newBmpGraphics = Graphics.FromImage(newBmp);
//Set the interpolation mode to high quality bicubic
//interpolation, to maximize the quality of the scaled image
newBmpGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
newBmpGraphics.ScaleTransform((float)xScaleFactor, (float)yScaleFactor);
//Draw the bitmap in the graphics object, which will apply
//the scale transform
//Note that pixel units must be specified to ensure the framework doesn't attempt
//to compensate for varying horizontal resolutions in images by resizing; in this case,
//that's the opposite of what we want.
Rectangle drawRect = new Rectangle(0, 0, inputBmp.Size.Width, inputBmp.Size.Height);
newBmpGraphics.DrawImage(inputBmp, drawRect, drawRect, GraphicsUnit.Pixel);
//Return the bitmap, as the operations on the graphics object
//are applied to the bitmap
newBmpGraphics.Dispose();
//newBmp will have a RawFormat of MemoryBmp because it was created
//from scratch instead of being based on inputBmp. Since it it inconvenient
//for the returned version of a bitmap to be of a different format, now convert
//the scaled bitmap to the format of the source bitmap
return ConvertBitmap(newBmp, inputBmp.RawFormat);
}
/// <summary>
/// Resizes a bitmap's width and height independently
/// </summary>
/// <param name="inputBmp">Bitmap to resize</param>
/// <param name="imgWidth">New width</param>
/// <param name="imgHeight">New height</param>
/// <returns>Resized bitmap</returns>
public static Bitmap ResizeBitmap(Bitmap inputBmp, int imgWidth, int imgHeight) {
//Simply compute scale factors that result in the desired size, then call ScaleBitmap
return ScaleBitmap(inputBmp,
(float)imgWidth/(float)inputBmp.Size.Width,
(float)imgHeight/(float)inputBmp.Size.Height);
}
/// <summary>
/// Generates a thumbnail of the bitmap. This is effectively a specialized
/// resize function, which maintains the aspect ratio of the image while
/// resizing it to ensure that both its width and height are within
/// caller-specified maximums
/// </summary>
/// <param name="inputBmp">Bitmap for which to generate thumbnail</param>
/// <param name="maxWidth">Maximum width of thumbnail</param>
/// <param name="maxHeight">Maximum height of thumbnail</param>
/// <returns>Thumbnail of inputBmp w/ the same aspect ratio, but
/// width and height both less than or equal to the maximum limits</returns>
public static Bitmap ThumbnailBitmap(Bitmap inputBmp, int maxWidth, int maxHeight) {
//Compute the scaling factor that will scale the bitmap witdh
//to the max width, and the other scaling factor that will scale
//the bitmap height to the max height.
//Apply the lower of the two, then if the other dimension is still
//outside the caller-defined limits, compute the scaling factor
//which will bring that dimension within the limits.
double widthScaleFactor = (double)maxWidth / (double)inputBmp.Size.Width;
double heightScaleFactor = (double)maxHeight / (double)inputBmp.Size.Height;
double finalScaleFactor = 0;
//Now pick the smaller scale factor
if (widthScaleFactor < heightScaleFactor) {
//If this scale factor doesn't bring the height
//within the required maximum, combine this width
//scale factor with an additional scaling factor
//to take the height the rest of the way down
if ((double)inputBmp.Size.Height * widthScaleFactor > maxHeight) {
//Need to scale height further
heightScaleFactor = (double)(maxHeight*widthScaleFactor) / (double)inputBmp.Size.Height;
finalScaleFactor = widthScaleFactor * heightScaleFactor;
} else {
//Width scale factor brings both dimensions inline sufficiently
finalScaleFactor = widthScaleFactor;
}
} else {
//Else, height scale factor is smaller than width.
//Apply the same logic as above, but with the roles of the width
//and height scale factors reversed
if ((double)inputBmp.Size.Width * heightScaleFactor > maxWidth) {
//Need to scale height further
widthScaleFactor = (double)(maxWidth*heightScaleFactor) / (double)inputBmp.Size.Width;
finalScaleFactor = widthScaleFactor * heightScaleFactor;
} else {
//Height scale factor brings both dimensions inline sufficiently
finalScaleFactor = heightScaleFactor;
}
}
return ScaleBitmap(inputBmp, finalScaleFactor);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -