Since the source Image seems to be a Color Image (that just happens to look like Black&White) and its dimensions need to be adjusted to a maximum value, you need to:
- Redefine proportionally the Size of the source Image, setting the maximum Width and Height limits that the converted image needs to respect
- Convert the Image to a
1bpp Indexed
format: the Bitmap.Clone() method provides means to both define the source Image new Size and set a specific PixelFormat (PixelFormat.Format1bppIndexed
, in this case). The internal conversion method is quite good, the resulting Image quality is usually a good compromise.
- Define the quality of the Image: since the Image will be converted to B&W, its quality can be set initially to the maximum (
100
). The process can be repeated if the final Image bytes count doesn't fit the requirements (50KB
)
- Compress the Image using the CCTII Group 4 Compression scheme
- Encode the Image, using the TIFF format Encoder, saving it to a
MemoryStream
for further processing
The size in bytes of the sample Image provided in the question, when saved to a file, is reduced from the initial 94,600
bytes to 6,786
bytes with maximum quality.
File.WriteAllBytes("[Image Path].tiff", imageStream.ToArray());
The ConvertToBWTiffImageStream()
method can be called as:
var maximumWidthAndHeight = new Size(1024, 768);
int quality = 100;
var compression = EncoderValue.CompressionCCITT4;
var imageStream = ConvertToBWTiffImageStream(sourceImage, maximumWidthAndHeight, quality, compression);
Note that maximumWidthAndHeight
specify the maximum Width and the maximum Height, not a new Size of the Image (which would be otherwise distorted). The Image Size is scaled proportionally according to these values.
► Remember to add this: using ImageCodec = System.Drawing.Imaging.Encoder;
(the GetImageMaxSize()
method is half-dumb, I'll fix it later)
using System.Drawing;
using System.Drawing.Imaging;
using ImageCodec = System.Drawing.Imaging.Encoder;
private MemoryStream ConvertToBWTiffImageStream(Bitmap image, Size maxWidthHeight, long compressionLevel, EncoderValue compressionScheme)
{
var imageSize = GetImageMaxSize(image, maxWidthHeight);
var bwImage = image.Clone(new Rectangle(Point.Empty, image.Size), PixelFormat.Format1bppIndexed);
compressionLevel = Math.Max(0, Math.Min(100, compressionLevel));
var codecParms = new EncoderParameters(2);
try {
var imageCodec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(enc => enc.FormatID == ImageFormat.Tiff.Guid);
var qualityParam = new EncoderParameter(ImageCodec.Quality, compressionLevel);
var compressionParam = new EncoderParameter(ImageCodec.Compression, (long)compressionScheme);
var ms = new MemoryStream();
codecParms.Param[0] = qualityParam;
codecParms.Param[1] = compressionParam;
image.Save(ms, imageCodec, codecParms);
return ms;
}
finally {
codecParms.Dispose();
bwImage.Dispose();
}
}
private Size GetImageMaxSize(Image image, Size maxSize)
{
float scale = 1.0f;
if (image.Width > maxSize.Width && image.Width >= image.Height) {
scale = (float)maxSize.Width / image.Width;
}
else if (image.Height > maxSize.Height) {
scale = (float)maxSize.Height / image.Height;
}
return new Size((int)(image.Width * scale), (int)(image.Height * scale));
}