毫秒级的时间处理上G的图片(生成缩略图)
2016-06-07 08:12
274 查看
测试环境:
View Code
测试结果:
using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Drawing.Drawing2D; namespace 缩略图查看 { /// <summary> /// Allows reading of embedded thumbnail image from the EXIF information in an image. /// </summary> //public abstract class ExifThumbReader public class ExifThumbReader { // GDI plus functions [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern int GdipGetPropertyItem(IntPtr image, int propid, int size, IntPtr buffer); [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern int GdipGetPropertyItemSize(IntPtr image, int propid, out int size); [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern int GdipLoadImageFromFile(string filename, out IntPtr image); [DllImport("gdiplus.dll", EntryPoint = "GdipDisposeImage", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int GdipDisposeImage(IntPtr image); // EXIT tag value for thumbnail data. Value specified by EXIF standard private static int THUMBNAIL_DATA = 0x501B; /// <summary> /// Reads the thumbnail in the given image. If no thumbnail is found, returns null /// </summary> //public static Image ReadThumb(string imagePath) public Image ReadThumb(string imagePath) { const int GDI_ERR_PROP_NOT_FOUND = 19; // Property not found error const int GDI_ERR_OUT_OF_MEMORY = 3; IntPtr hImage = IntPtr.Zero; IntPtr buffer = IntPtr.Zero; // Holds the thumbnail data int ret; ret = GdipLoadImageFromFile(imagePath, out hImage); try { if (ret != 0) throw createException(ret); int propSize; ret = GdipGetPropertyItemSize(hImage, THUMBNAIL_DATA, out propSize); // Image has no thumbnail data in it. Return null if (ret == GDI_ERR_PROP_NOT_FOUND) return null; if (ret != 0) throw createException(ret); // Allocate a buffer in memory buffer = Marshal.AllocHGlobal(propSize); if (buffer == IntPtr.Zero) throw createException(GDI_ERR_OUT_OF_MEMORY); ret = GdipGetPropertyItem(hImage, THUMBNAIL_DATA, propSize, buffer); if (ret != 0) throw createException(ret); // buffer has the thumbnail data. Now we have to convert it to // an Image return convertFromMemory(buffer); } finally { // Free the buffer if (buffer != IntPtr.Zero) Marshal.FreeHGlobal(buffer); GdipDisposeImage(hImage); } } /// <summary> /// Generates an exception depending on the GDI+ error codes (I removed some error /// codes) /// </summary> private static Exception createException(int gdipErrorCode) { switch (gdipErrorCode) { case 1: return new ExternalException("Gdiplus Generic Error", -2147467259); case 2: return new ArgumentException("Gdiplus Invalid Parameter"); case 3: return new OutOfMemoryException("Gdiplus Out Of Memory"); case 4: return new InvalidOperationException("Gdiplus Object Busy"); case 5: return new OutOfMemoryException("Gdiplus Insufficient Buffer"); case 7: return new ExternalException("Gdiplus Generic Error", -2147467259); case 8: return new InvalidOperationException("Gdiplus Wrong State"); case 9: return new ExternalException("Gdiplus Aborted", -2147467260); case 10: return new FileNotFoundException("Gdiplus File Not Found"); case 11: return new OverflowException("Gdiplus Over flow"); case 12: return new ExternalException("Gdiplus Access Denied", -2147024891); case 13: return new ArgumentException("Gdiplus Unknown Image Format"); case 18: return new ExternalException("Gdiplus Not Initialized", -2147467259); case 20: return new ArgumentException("Gdiplus Property Not Supported Error"); } return new ExternalException("Gdiplus Unknown Error", -2147418113); } /// <summary> /// Converts the IntPtr buffer to a property item and then converts its /// value to a Drawing.Image item /// </summary> private static Image convertFromMemory(IntPtr thumbData) { propertyItemInternal prop = (propertyItemInternal)Marshal.PtrToStructure (thumbData, typeof(propertyItemInternal)); // The image data is in the form of a byte array. Write all // the bytes to a stream and create a new image from that stream byte[] imageBytes = prop.Value; MemoryStream stream = new MemoryStream(imageBytes.Length); stream.Write(imageBytes, 0, imageBytes.Length); return Image.FromStream(stream); } /// <summary> /// Used in Marshal.PtrToStructure(). /// We need this dummy class because Imaging.PropertyItem is not a "blittable" /// class and Marshal.PtrToStructure only accepted blittable classes. /// (It's not blitable because it uses a byte[] array and that's not a blittable /// type. See MSDN for a definition of Blittable.) /// </summary> [StructLayout(LayoutKind.Sequential)] private class propertyItemInternal { public int id = 0; public int len = 0; public short type = 0; public IntPtr value = IntPtr.Zero; public byte[] Value { get { byte[] bytes = new byte[(uint)len]; Marshal.Copy(value, bytes, 0, len); return bytes; } } } } }
View Code
测试结果:
方法 | 图片张数(张) | 每张大小(M) | 图片总大小 | 用时 |
方法一 | 50 | 30 | 1500M | 39950毫秒=40秒 |
方法二 | 50 | 30 | 1500M | 66450毫秒=66秒 |
方法三 | 50 | 30 | 1500M | 81800毫秒=81秒 |
方法四 | 50 | 30 | 1500M | 83200毫秒=83秒 |
方法五 | 50 | 30 | 1500M | 36750毫秒=37秒 |
方法六 | 50 | 30 | 1500M | 237毫秒 |
方法七 | 50 | 30 | 1500M | 96毫秒 |