1
votes

I m trying to compress tiff file with CCITT4. Original size 101 KB, after run size reduce a little 98 KB. My limit size 50 KB, how can I make the size under my limit? code is below

My limits; Size <50KB
Image Width: 1766 – 1890 pixels Image Length: 915 – 1040 pixels

Thanks everyone. Image Sample

public static Byte[] CompressBitmap(Bitmap img)
    {
        Bitmap bm = img;
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
        ImageCodecInfo ici = null;
        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.MimeType == "image/tiff")
                ici = codec;
        }

        EncoderParameters ep = new EncoderParameters(1);
        ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, 
                    (long)EncoderValue.Flush);
        ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 
                    (long)EncoderValue.CompressionCCITT4);
        using (var stream = new MemoryStream())
        {
            bm.Save(stream, ici, ep);
            return stream.ToArray();
        }
    }
1
These are black and white images right?Zer0
Right, black and white images, also i have dimension limits (1766, 915)Erkan Sönmez
What is the source Image PixelFormat set to? Have you tried RLE compression? Do you need just the byte array or do you generate a new Image? In this case, what is the PixelFormat after the new Image is generated?Jimi
Also, Group 4 generates a pretty low quality Image. Are you sure you want this? Do you need these Images to have the TIFF format, or another format may also do (if you care more about compression)?Jimi
Exactly i dont know the source image PixelFormat, first I resize source image and clone it then run compress algorithm. I need byte array at the end, but dont try RLE compression, I should compress result file with CCITT4. can i use PixelFormat to reduce the size?Erkan Sönmez

1 Answers

0
votes

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:

  1. Redefine proportionally the Size of the source Image, setting the maximum Width and Height limits that the converted image needs to respect
  2. 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.
  3. 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)
  4. Compress the Image using the CCTII Group 4 Compression scheme
  5. 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));
}