将多个图片合并到一个TIF文件里(非 GDAL) 优化版

不知道为什么,网上对TIF的操作的资料少得可怜,包括CodeProject上都没有找到多少,在网上大多用GDAL,但这个东西,对只想做个合并图片的功能来说,实在是牛刀杀鸡,(9个DLL要带全,相当的恐怖)而且对完成的生成和读取TIF的描述也是相当的少,一般都是用来处理GIS。
版本为优化版,原版经常报内存不足
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace Common
{
 
    public class CreatTiff 
    {
        #region 将图片列表合并到一个文件
        /// <summary>
        /// 多张图片合并
        /// </summary>
        /// <param name="img">图片列表</param>
        /// <param name="dstFile">合并图片名</param>
        /// <returns></returns>
        public bool CreateTiffFile(Image[] img, string dstFile) { 
            return GetTiffFile(img, dstFile);
        }
        #endregion

        #region 将单个TIF添加到多页TIF中
        /// <summary>
        /// 将单个TIF添加到多页TIF中
        /// </summary>
        /// <param name="srcFile">单页TIFF地址</param>
        /// <param name="dstFile">需要添加到的多页TIFF地址</param>
        /// <returns></returns>
        public bool AddTiffFile(string srcFile, string dstFile, string RootPath, int tifNumber)
        {
            try
            {
                string thumbnailImagePath = RootPath + "thumbnailImagePath.tif";
                Image i1 = null;
                //if (tifNumber > 9)//为解决内存不足想的拙劣解决方法
                //{
                //    GetThumbnail(srcFile, thumbnailImagePath, 1150, 1850);
                //    i1 = Image.FromFile(thumbnailImagePath);
                //}
                //else
                //{
                //    i1 = Image.FromFile(srcFile);
                //}
                i1 = Image.FromFile(srcFile);
                Image loadImage = new Bitmap(i1);

                Image origionalFile = Image.FromFile(dstFile);
                int PageNumber = getPageNumber(origionalFile);
                Image[] img = new Image[PageNumber + 1];
                for (int i = 0; i < PageNumber; i++)
                {
                    origionalFile.SelectActiveFrame(FrameDimension.Page, i);
                    img[i] = new Bitmap(origionalFile);
                }
                img[PageNumber] = loadImage;
                origionalFile.Dispose();
                i1.Dispose();
                return GetTiffFile(img, dstFile);
            }
            catch (Exception ex)
            {
                Log.Writer(ex, "合并TIF文件AddTiffFile()异常");
                throw new Exception("TIF文件:"+ srcFile + "  处理错误!请检查文件是否损坏!");
            }
        }
        #endregion

        #region 合并
        /// <summary>
        /// 合并
        /// </summary>
        /// <param name="img">图片列表</param>
        /// <param name="dstFile">合并目的文件</param>
        /// <returns></returns>
        private bool GetTiffFile(Image[] img, string dstFile)
        {
            EncoderParameter SaveEncodeParam = null;
            EncoderParameter CompressionEncodeParam = null;
            EncoderParameters EncoderParams = null;
            try
            {
                if (img == null) return false;
                if (img.Length < 2) return false;//如果只有一个文件,直接存成TIFF就好了,没有必要在这里处理
                ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders()[3];
                if (codecInfo.FormatDescription != "TIFF") return false;

                for (int i = 0; i < img.Length; i++)
                {
                    if (img[i] == null)
                        break;
                    img[i] = (Image)ConvertToBitonal((Bitmap)img[i]);

                }
                if (img.Length < 2) return false;

                Encoder saveEncoder = Encoder.SaveFlag;
                Encoder compressionEncoder = Encoder.Compression;
                SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.MultiFrame);
                CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionCCITT4);
                EncoderParams = new EncoderParameters(2);
                EncoderParams.Param[0] = CompressionEncodeParam;
                EncoderParams.Param[1] = SaveEncodeParam;

                if (File.Exists(dstFile)) File.Delete(dstFile);


                img[0].Save(dstFile, codecInfo, EncoderParams);
                for (int i = 1; i < img.Length; i++)
                {
                    SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.FrameDimensionPage);
                    CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionCCITT4);
                    EncoderParams.Param[0] = CompressionEncodeParam;
                    EncoderParams.Param[1] = SaveEncodeParam;
                    img[0].SaveAdd(img[i], EncoderParams);

                }

                SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.Flush);
                EncoderParams.Param[0] = SaveEncodeParam;
                img[0].SaveAdd(EncoderParams);
            }
            catch (Exception ex)
            {
                Log.Writer(ex, "合并TIF文件异常");
                return false;
            }
            finally
            {
                SaveEncodeParam.Dispose();
                CompressionEncodeParam.Dispose();
                EncoderParams.Dispose();
                foreach (var item in img)
                {
                    item.Dispose();
                }
                GC.Collect();
            }
            return true;
        }
        #endregion

        /// <summary>
        /// 生成缩略图
        /// </summary>
        /// <param name="serverImagePath">图片地址</param>
        /// <param name="thumbnailImagePath">缩略图地址</param>
        /// <param name="width">图片宽度</param>
        /// <param name="height">图片高度</param>
        /// <param name="p"></param>
        public static void GetThumbnail(string serverImagePath, string thumbnailImagePath, int width, int height)
        {
            System.Drawing.Image serverImage = System.Drawing.Image.FromFile(serverImagePath);
            //画板大小
            int towidth = width;
            int toheight = height;
            //缩略图矩形框的像素点
            //int x = 0;
            //int y = 0;
            int ow = serverImage.Width;
            int oh = serverImage.Height;

            if (ow > oh)
            {
                toheight = serverImage.Height * width / serverImage.Width;
            }
            else
            {
                towidth = serverImage.Width * height / serverImage.Height;
            }
            //新建一个bmp图片
            System.Drawing.Image bm = new System.Drawing.Bitmap(width, height);
            //新建一个画板
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bm);
            //设置高质量插值法
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            //设置高质量,低速度呈现平滑程度
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //清空画布并以透明背景色填充
            g.Clear(System.Drawing.Color.White);
            //在指定位置并且按指定大小绘制原图片的指定部分
            g.DrawImage(serverImage, new System.Drawing.Rectangle((width - towidth) / 2, (height - toheight) / 2, towidth, toheight),
                0, 0, ow, oh,
                System.Drawing.GraphicsUnit.Pixel);
            try
            {
                //以jpg格式保存缩略图
                bm.Save(thumbnailImagePath, System.Drawing.Imaging.ImageFormat.Tiff);
            }
            catch (System.Exception e)
            {
                throw e;
            }
            finally
            {
                serverImage.Dispose();
                bm.Dispose();
                g.Dispose();
                GC.Collect();
            }
        }

        private Bitmap ConvertToBitonal(Bitmap original)
        {
            Bitmap source = null;
            // If original bitmap is not already in 32 BPP, ARGB format, then convert
            if (original.PixelFormat != PixelFormat.Format32bppArgb)
            {
                source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
                source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
                using (Graphics g = Graphics.FromImage(source))
                {
                    g.DrawImageUnscaled(original, 0, 0);
                }
            }
            else
            {
                source = original;
            }

            // Lock source bitmap in memory
            BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            // Copy image data to binary array
            int imageSize = sourceData.Stride * sourceData.Height;
            byte[] sourceBuffer = new byte[imageSize];
            Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);

            // Unlock source bitmap
            source.UnlockBits(sourceData);

            // Create destination bitmap
            Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);

            // Lock destination bitmap in memory
            BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            // Create destination buffer
            imageSize = destinationData.Stride * destinationData.Height;
            byte[] destinationBuffer = new byte[imageSize];

            int sourceIndex = 0;
            int destinationIndex = 0;
            int pixelTotal = 0;
            byte destinationValue = 0;
            int pixelValue = 128;
            int height = source.Height;
            int width = source.Width;
            int threshold = 500;

            // Iterate lines
            for (int y = 0; y < height; y++)
            {
                sourceIndex = y * sourceData.Stride;
                destinationIndex = y * destinationData.Stride;
                destinationValue = 0;
                pixelValue = 128;

                // Iterate pixels
                for (int x = 0; x < width; x++)
                {
                    // Compute pixel brightness (i.e. total of Red, Green, and Blue values)
                    pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];
                    if (pixelTotal > threshold)
                    {
                        destinationValue += (byte)pixelValue;
                    }
                    if (pixelValue == 1)
                    {
                        destinationBuffer[destinationIndex] = destinationValue;
                        destinationIndex++;
                        destinationValue = 0;
                        pixelValue = 128;
                    }
                    else
                    {
                        pixelValue >>= 1;
                    }
                    sourceIndex += 4;
                }
                if (pixelValue != 128)
                {
                    destinationBuffer[destinationIndex] = destinationValue;
                }
            }
            // Copy binary image data to destination bitmap
            Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
            // Unlock destination bitmap
            destination.UnlockBits(destinationData);
            // Return
            return destination;
        }

        private int getPageNumber(Image img)
        {
            Guid objGuid = img.FrameDimensionsList[0];
            FrameDimension objDimension = new FrameDimension(objGuid);
            //Gets the total number of frames in the .tiff file
            int PageNumber = img.GetFrameCount(objDimension);
            return PageNumber;
        }

        
    }
}
原文地址:https://www.cnblogs.com/lee2011/p/6065830.html