Image.Save() on MemoryBmp to TIFF with EncoderParams - How?
I have an application that allows a user to define a region of an image and save that region to file. I have run up against a snag that I can't sort out. The Bitmap that I create to paint the selected region onto is stuck with an ImageFormat of "MemoryBmp", it appears that this is the ImageFormat that is set for any non-file loaded bitmaps. The problem is my Bitmap is created in memory and I want to save it as a CCITT4 bitonal TIFF but I'm getting a "A generic error occurred in GDI+" Exception. I'm pretty confident this is due to the fact the Image.RawFormat property is that dreaded MemoryBmp.
Image.Save() has an overload that takes an ImageFormat parameter and when I use that passing ImageFormat.Tiff it saves fine, but I don't get the opportunity to specify my encoder parameters.
The only possible workaround I can think of is to save to disk using Image.Save(Image, ImageFormat) then reload it (RawFormat will now correctly be set to ImageFormat.Tif) and THEN save again passing the encoder settings. That is just stupid though, there must be a better way.
Here is a snipped of code (this is just testing stuff) that should give you an idea of what I'm doing in case my earlier description wasn't clear enough:
SizeF dpiScale = GetScreenToImageDPIRatio(loadedImage);
using (Bitmap image = new Bitmap(loadedImage,
(int)(_cropBox.Width * dpiScale.Width),
(int)(_cropBox.Height * dpiScale.Height)))
{
image.SetResolution(loadedImage.HorizontalResolution,
loadedImage.VerticalResolution);
using (Graphics g = Graphics.FromImage(image))
{
g.DrawImage(loadedImage, 0, 0, new Rectangle(
(int)(_c开发者_开发问答ropBox.Location.X * dpiScale.Width),
(int)(_cropBox.Location.Y * dpiScale.Height),
(int)(_cropBox.Width * dpiScale.Width),
(int)(_cropBox.Height * dpiScale.Height)),
GraphicsUnit.Pixel);
}
// It's stuck as a MemoryBmp so none of these checks will work
if (true || image.RawFormat.Equals(ImageFormat.Tiff))
{
ImageCodecInfo tiffCodecInfo = ImageUtils.GetEncoderInfo("image/tiff");
EncoderParameters myEncoderParameters = new EncoderParameters(2);
myEncoderParameters.Param[0] = new
EncoderParameter(System.Drawing.Imaging.Encoder.Compression,
(long)EncoderValue.CompressionCCITT4);
myEncoderParameters.Param[1] = new
EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 1L);
image.Save(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".tif"),
tiffCodecInfo, myEncoderParameters);
// The file is a "MemoryBmp" and it's screwing things up
//image.Save(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".tif"),
// ImageFormat.Tiff);
}
else
{
// other format saving support, blah blah blah
}
}
Oh, I should mention that "loadedIimage" is indeed a tiff image, I passed the reference to loadedImage to the Bitmap.ctor() to see if that would clue it in to what it's dealing with but it made no difference.
Figured out that CCITT4 DOES require bi-tonal images, ha! So I went off googling and came across a CodeProject article and snooped around in the source. The author provided a pretty decent method to convert 32bppARGB to 1bpp bi-tonal. I tried it out and it's fast (test show around 34 ms for a single page) and it did the trick!
I'm answering my own question. I hope this at least helps someone else who comes across this problem.
精彩评论