//using Microsoft.WindowsAPICodePack.Shell;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace HStation.RevitDev.RevitDataExport.Common
{
public class ThumbnailUtils
{
//public static Bitmap GetThumbnail(string rfaFile)
//{
// if (!File.Exists(rfaFile))
// {
// throw new Exception($"{rfaFile}文件不存在!无法获取文件缩略图!");
// }
// ShellObject so = ShellFile.FromFilePath(rfaFile);
// Bitmap bitmap = so.Thumbnail.LargeBitmap;
// return bitmap;
//}
public static Bitmap GetThumbnailWithoutRevit(string rfaFile)
{
string savePath = Path.GetDirectoryName(rfaFile) + "\\" + Path.GetFileNameWithoutExtension(rfaFile) + ".png";
try
{
GetImage(rfaFile, savePath);
}
catch (Exception ex)
{
//throw new Exception($"获取rfa文件缩略图出错!{ex.Message}");
}
Bitmap bitmap = new Bitmap(savePath);
return bitmap;
}
private static object InvokeStorageRootMethod(StorageInfo storageRoot, string methodName, params object[] methodArgs)
{
BindingFlags bindingFlags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.InvokeMethod;
Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot",
true,
false);
object result = storageRootType.InvokeMember(methodName,
bindingFlags,
null,
storageRoot,
methodArgs);
return result;
}
///
/// 获取缩略图
///
///
///
private static void GetImage(string file, string savePath)
{
int bitmapSize = Common.GlobalResource.ThumbnailSize;
try
{
StorageInfo storageRoot = (StorageInfo)InvokeStorageRootMethod(null,
"Open",
file,
FileMode.Open,
FileAccess.Read,
FileShare.Read);
if (storageRoot == null)
{
return;
}
byte[] preViewData = null;
StreamInfo[] streams = storageRoot.GetStreams();
foreach (StreamInfo stream in streams)
{
if (stream.Name.ToUpper().Equals("REVITPREVIEW4.0"))
{
preViewData = ParsePreviewInfo(stream);
}
}
InvokeStorageRootMethod(storageRoot, "Close");
// 获取不到信息返回一个100x100的空图片
if (preViewData == null || preViewData.Length <= 0)
{
using (Bitmap newBitmap = new Bitmap(bitmapSize, bitmapSize))
{
newBitmap.Save(savePath);
return;
}
}
// 通过Revit元数据读取到PNG图像的开头
int startingOffset = GetPngStartingOffset(preViewData);
if (startingOffset == 0)
{
using (Bitmap newBitmap = new Bitmap(bitmapSize, bitmapSize))
{
newBitmap.Save(savePath);
return;
}
}
byte[] pngDataBuffer = new byte[preViewData.GetUpperBound(0) - startingOffset + 1];
// 将PNG图像数据读入字节数组
using (MemoryStream ms = new MemoryStream(preViewData))
{
ms.Position = startingOffset;
ms.Read(pngDataBuffer, 0, pngDataBuffer.Length);
}
byte[] decoderData = null;
// 如果图像数据有效
if (pngDataBuffer != null)
{
// 使用内存流对PNG图像数据进行解码
// 并将解码后的数据复制到字节数组中
using (MemoryStream ms = new MemoryStream(pngDataBuffer))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
decoderData = BitSourceToArray(decoder.Frames[0]);
}
}
// 如果解码的数据有效
if ((decoderData != null) && (decoderData.Length > 0))
{
// 使用另一个内存流创建Bitmap
// 然后是一张图片Bitmap
using (MemoryStream ms = new MemoryStream(decoderData))
{
using (Bitmap newBitmap = new Bitmap((ms)))
{
newBitmap.Save(savePath);
return;
}
}
}
using (Bitmap newBitmap = new Bitmap(bitmapSize, bitmapSize))
{
newBitmap.Save(savePath);
}
}
catch (Exception)
{
Bitmap newBitmap = new Bitmap(bitmapSize, bitmapSize);
newBitmap.Save(savePath);
}
}
private static byte[] ParsePreviewInfo(StreamInfo streamInfo)
{
byte[] streamData = null;
try
{
using (Stream streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
return streamData;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
streamData = null;
}
}
private static byte[] BitSourceToArray(BitmapSource bitmapSource)
{
BitmapEncoder encoder = new JpegBitmapEncoder();
using (MemoryStream ms = new MemoryStream())
{
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(ms);
return ms.ToArray();
}
}
private static int GetPngStartingOffset(byte[] previewData)
{
bool markerFound = false;
int startingOffset = 0;
int previousValue = 0;
using (MemoryStream ms = new MemoryStream(previewData))
{
for (int i = 0; i < previewData.Length; i++)
{
int currentValue = ms.ReadByte();
// possible start of PNG file data
if (currentValue == 137) // 0x89
{
markerFound = true;
startingOffset = i;
previousValue = currentValue;
continue;
}
switch (currentValue)
{
case 80: // 0x50
if (markerFound && (previousValue == 137))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 78: // 0x4E
if (markerFound && (previousValue == 80))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 71: // 0x47
if (markerFound && (previousValue == 78))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 13: // 0x0D
if (markerFound && (previousValue == 71))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 10: // 0x0A
if (markerFound && (previousValue == 26))
{
return startingOffset;
}
if (markerFound && (previousValue == 13))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 26: // 0x1A
if (markerFound && (previousValue == 10))
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
}
}
}
return 0;
}
}
}