Размер изображения в байтах увеличивается после разделения и объединения файла Tiff

Я пытаюсь разделить и объединить многостраничное изображение в формате TIFF. Причина, по которой я разделяю, заключается в том, чтобы рисовать аннотации на каждом уровне изображения. Код работает нормально, однако объединенный TIFF довольно большой по сравнению с исходным TIFF. Например, я протестировал TIFF-изображение с 17 цветными страницами (размер 5 МБ), после разделения и слияния он создает TIFF-изображение размером 85 МБ. Я использую BitMiracle.LibTiff. Я также временно прокомментировал код аннотаций, чтобы решить эту проблему с размером, я не уверен, что делаю неправильно. Вот код для разделения.

private List<Bitmap> SplitTiff(byte[] imageData)
{
    var bitmapList = new List<Bitmap>();
    var tiffStream = new TiffStreamForBytes(imageData);

    //open tif file
    var tif = Tiff.ClientOpen("", "r", null, tiffStream);

    //get number of pages
    var num = tif.NumberOfDirectories();
    if (num == 1) 
        return new List<Bitmap> 
        { 
            new Bitmap(GetImage(imageData)) 
        };

    for (short i = 0; i < num; i++)
    {
         //set current page
         tif.SetDirectory(i);
         FieldValue[] photoMetric = tif.GetField(TiffTag.PHOTOMETRIC);
         Photometric photo = Photometric.MINISBLACK;
         if (photoMetric != null && photoMetric.Length > 0)
             photo = (Photometric)photoMetric[0].ToInt();

         if (photo != Photometric.MINISBLACK && photo != Photometric.MINISWHITE)
             bitmapList.Add(GetBitmapFromTiff(tif));
         // else
             // bitmapList.Add(GetBitmapFromTiffBlack(tif, photo));// commented temporrarly to fix size issue
     }
     return bitmapList;
}

private static Bitmap GetBitmapFromTiff(Tiff tif)
{
    var value = tif.GetField(TiffTag.IMAGEWIDTH);
    var width = value[0].ToInt();

    value = tif.GetField(TiffTag.IMAGELENGTH);
    var height = value[0].ToInt();

    //Read the image into the memory buffer
    var raster = new int[height * width];
    if (!tif.ReadRGBAImage(width, height, raster))
    {
        return null;
    }

    var bmp = new Bitmap(width, height, PixelFormat.Format32bppRgb);

    var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

    var bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
    var bits = new byte[bmpdata.Stride * bmpdata.Height];

    for (var y = 0; y < bmp.Height; y++)
    {
        int rasterOffset = y * bmp.Width;
        int bitsOffset = (bmp.Height - y - 1) * bmpdata.Stride;

        for (int x = 0; x < bmp.Width; x++)
        {
            int rgba = raster[rasterOffset++];
            bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff);
            bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff);
            bits[bitsOffset++] = (byte)(rgba & 0xff);
            bits[bitsOffset++] = (byte)((rgba >> 24) & 0xff);
         }
    }

    System.Runtime.InteropServices.Marshal.Copy(bits, 0, bmpdata.Scan0, bits.Length);
    bmp.UnlockBits(bmpdata);

    return bmp;
}

и код для объединения отдельных растровых изображений в TIFF находится здесь...

public static PrizmImage PrizmImageFromBitmaps(List<Bitmap> imageItems, string ext)
{
     if (imageItems.Count == 1 && !(ext.ToLower().Equals(".tif") || ext.ToLower().Equals(".tiff")))
         return new PrizmImage(new MemoryStream(ImageUtility.BitmapToByteArray(imageItems[0])), ext);

     var codecInfo = GetCodecInfo();
     var memoryStream = new MemoryStream();

     var encoderParams = new EncoderParameters(1);
     encoderParams.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.MultiFrame);

     var initialImage = imageItems[0];
     var masterBitmap = imageItems[0];// new Bitmap(initialImage);
     masterBitmap.Save(memoryStream, codecInfo, encoderParams);
     encoderParams.Param[0] = new EncoderParameter(Encoder.SaveFlag,  (long)EncoderValue.FrameDimensionPage);

     for (var i = 1; i < imageItems.Count; i++)
     {
          var img = imageItems[i];
          masterBitmap.SaveAdd(img, encoderParams);
          img.Dispose();
     }

     encoderParams.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.Flush);
     masterBitmap.SaveAdd(encoderParams);

     memoryStream.Seek(0, SeekOrigin.Begin);
     encoderParams.Dispose();
     masterBitmap.Dispose();
     return new PrizmImage(memoryStream, ext);
}

person Hari Narisetty    schedule 06.01.2014    source источник
comment
Пожалуйста, разместите ссылки на образцы изображений до и после, и я смогу рассказать вам, почему размеры такие разные. Вероятно, это связано с неоптимальным методом/параметрами кодирования.   -  person BitBank    schedule 07.01.2014
comment
Как я могу отправить вам изображения? Можете ли вы отправить тестовое письмо на адрес [email protected], чтобы я мог отправить изображения?   -  person Hari Narisetty    schedule 07.01.2014


Ответы (1)


Скорее всего, проблема связана с тем, что вы конвертируете все изображения в растровые изображения с разрешением 32 бита на пиксель.

Предположим, у вас есть черно-белое изображение, закодированное по факсу. Он может быть закодирован как файл TIFF размером 100 Кб. Одно и то же изображение может занять более 10 мегабайт, если вы сохраните его как растровое изображение с разрешением 32 бита на пиксель. Сжатие этих мегабайтов поможет, но вы никогда не достигнете той же степени сжатия, что и в исходном изображении, потому что вы увеличили объем данных изображения с 1 бита на пиксель до 32 битов на пиксель.

Таким образом, вы не должны преобразовывать изображения в растровые изображения 32bpp, если это возможно. Постарайтесь максимально сохранить их свойства и сжатие. Взгляните на исходный код утилиты TiffCP, чтобы узнать, как это сделать.

Если вам абсолютно необходимо преобразовать изображения в растровые изображения с разрешением 32 бита на пиксель (возможно, вам придется это сделать, если вы добавите к ним красочные аннотации), то мало что можно сделать для уменьшения результирующего размера. Вы можете уменьшить размер вывода на 10-20% процентов, если выберете лучшую схему сжатия и правильно настроите схему. Но это все, боюсь.

person Bobrovsky    schedule 07.01.2014
comment
Спасибо. Мне не нужно сохранять растровое изображение 32bpp... как мне изменить приведенный выше код, чтобы использовать наименьшее количество битов на пиксель? - person Hari Narisetty; 07.01.2014