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

时间:2023-12-17 21:18:44
不知道为什么,网上对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 + ];
for (int i = ; 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 < ) return false;//如果只有一个文件,直接存成TIFF就好了,没有必要在这里处理
ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders()[];
if (codecInfo.FormatDescription != "TIFF") return false; for (int i = ; i < img.Length; i++)
{
if (img[i] == null)
break;
img[i] = (Image)ConvertToBitonal((Bitmap)img[i]); }
if (img.Length < ) 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();
EncoderParams.Param[] = CompressionEncodeParam;
EncoderParams.Param[] = SaveEncodeParam; if (File.Exists(dstFile)) File.Delete(dstFile); img[].Save(dstFile, codecInfo, EncoderParams);
for (int i = ; i < img.Length; i++)
{
SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.FrameDimensionPage);
CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionCCITT4);
EncoderParams.Param[] = CompressionEncodeParam;
EncoderParams.Param[] = SaveEncodeParam;
img[].SaveAdd(img[i], EncoderParams); } SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.Flush);
EncoderParams.Param[] = SaveEncodeParam;
img[].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) / , (height - toheight) / , towidth, toheight),
, , 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, , );
}
}
else
{
source = original;
} // Lock source bitmap in memory
BitmapData sourceData = source.LockBits(new Rectangle(, , 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, , 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(, , destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); // Create destination buffer
imageSize = destinationData.Stride * destinationData.Height;
byte[] destinationBuffer = new byte[imageSize]; int sourceIndex = ;
int destinationIndex = ;
int pixelTotal = ;
byte destinationValue = ;
int pixelValue = ;
int height = source.Height;
int width = source.Width;
int threshold = ; // Iterate lines
for (int y = ; y < height; y++)
{
sourceIndex = y * sourceData.Stride;
destinationIndex = y * destinationData.Stride;
destinationValue = ;
pixelValue = ; // Iterate pixels
for (int x = ; x < width; x++)
{
// Compute pixel brightness (i.e. total of Red, Green, and Blue values)
pixelTotal = sourceBuffer[sourceIndex + ] + sourceBuffer[sourceIndex + ] + sourceBuffer[sourceIndex + ];
if (pixelTotal > threshold)
{
destinationValue += (byte)pixelValue;
}
if (pixelValue == )
{
destinationBuffer[destinationIndex] = destinationValue;
destinationIndex++;
destinationValue = ;
pixelValue = ;
}
else
{
pixelValue >>= ;
}
sourceIndex += ;
}
if (pixelValue != )
{
destinationBuffer[destinationIndex] = destinationValue;
}
}
// Copy binary image data to destination bitmap
Marshal.Copy(destinationBuffer, , destinationData.Scan0, imageSize);
// Unlock destination bitmap
destination.UnlockBits(destinationData);
// Return
return destination;
} private int getPageNumber(Image img)
{
Guid objGuid = img.FrameDimensionsList[];
FrameDimension objDimension = new FrameDimension(objGuid);
//Gets the total number of frames in the .tiff file
int PageNumber = img.GetFrameCount(objDimension);
return PageNumber;
} }
}