专栏首页一心无二用,本人只专注于基础图像算法的实现与优化。关于.net中获取图像缩略图的函数GetThumbnailImage的一些认识。

关于.net中获取图像缩略图的函数GetThumbnailImage的一些认识。

  在很多图像软件中,打开一幅图像的时候都会显示其缩略图,在看图软件中这样的需求更为常见。如何快速的获取缩略图的信息并提供给用户查看,是个值得研究的问题。在我所研究过的图像格式中,只有JPG和PSD两种格式可能内嵌了图像自身的缩略图信息。

  在.net中,图像处理方面的内容主要是借助于GDI+的平板化API函数实现的。为了获取GDI+能支持的那几种格式的缩略图,可以调用Bitmap或者Image类的GetThumbnailImage函数。用Reflecor反编译后知道,这个函数的主要实现代码如下所示:

public Image GetThumbnailImage(int thumbWidth, int thumbHeight, GetThumbnailImageAbort callback, IntPtr callbackData)
{
    IntPtr zero = IntPtr.Zero;
    int status = SafeNativeMethods.Gdip.GdipGetImageThumbnail(new HandleRef(this, this.nativeImage), thumbWidth, thumbHeight, out zero, callback, callbackData);
    if (status != 0)
    {
        throw SafeNativeMethods.Gdip.StatusException(status);
    }
    return CreateImageObject(zero);
}

  那么其实他也是直接调用GdipGetImageThumbnail函数。

下面我们主要通过实验说说这个函数的实质和其可应用的场合以及不应该应用的场合。

  为了测试公平,我们选用VB6作为测试语言,这有两个原因:(1)因为VB6直接调用GDI+的API函数很方便,也可以降低.net中创建各种对象所用的时间。(2)我在C#中调用Bitmap.FromFile读取文件的时间比VB6中使用同样的API要慢很多,不知道为什么。

结论1: 该函数首先判断图像是否内嵌了缩略图,如果有,则直接读取他,然后再将获得的缩略图缩放到用户调用时指定的大小。如果没有,则从图像数据中抽样填充到缩略图数据中,至于抽样算法,这个没有研究,也许是线性插值吧。

验证前的准备工作:

   (1) 一副4000*3000的数码照片,JPG格式,内嵌了缩略图信息(如何验证:可以用很多查看EXIF信息的软件查看),可在此处下载

(2) 一副4000*3000的照片,JPG格式,没有内嵌缩略图信息(如何验证:可以用很多查看EXIF信息的软件查看),可在此处下载

(3) 一副4000*3000的照片,Png格式,由于无法上传大于5MB的文件,请朋友自行用工具转换。

对上述三幅图像进行获取缩略图的操作,具体代码如下:

 '第一步:加载图像
    Elapse = GetTickCount
    GdipLoadImageFromFile StrPtr(FileName), Bitmap
    Result = Result + "加载图像用时:  " & GetTickCount - Elapse & "  毫秒。" + vbCrLf
    
    GdipGetImageWidth Bitmap, Width
    GdipGetImageHeight Bitmap, Height
    GetFitSize Width, Height, 600, 450, FitX, FitY, FitWidth, FitHeight
    
    '第二步:获取缩略图
    Elapse = GetTickCount
    GdipGetImageThumbnail Bitmap, FitWidth, FitHeight, Thumb
    Result = Result + "获取缩略图用时:  " & GetTickCount - Elapse & "  毫秒。" + vbCrLf
    
    GdipCreateFromHDC Hdc, Graphics
    
    '第三步:绘制缩略图
    Elapse = GetTickCount
    GdipDrawImageRect Graphics, Thumb, FitX, FitY, FitWidth, FitHeight
    Result = Result + "绘制缩略图:  " & GetTickCount - Elapse & "  毫秒。" + vbCrLf
    
    GdipDisposeImage Bitmap
    GdipDisposeImage Thumb
    GdipDeleteGraphics Graphics

我们依次查看结果:

            图1 : 内嵌了缩略图的JPG图像

                         图2: 未内嵌缩略图的JPG图像

                           图3: PNG图像

  上述缩略图的大小设置为600*450。

通过上面3个测试结果图的比较,可以明显看到: 内嵌了缩略图的JPG图像获得最后的缩略图很模糊,但是速度相当的块,而未内嵌了缩略图的JPG图像以及PNG图像获得的缩略图非常的清晰,但是耗时很多。因此我们可以初步的判断如果内嵌了缩略图,则GdipGetImageThumbnail会直接从内嵌的数据中进行缩放。为了进一步验证这一点,我生成了一副缩略图和原图完全不配套的JPG图像,来验证这一点,可从此处下载:

处理结果如下图:

可见,执行速度还是不错的,缩略图的结果却是错误的,但是和我们嵌入的缩略图却是一致的。

附带说一个问题:不知道大家注意到没有,上述代码中 GdipLoadImageFromFile 函数执行的时间都很短,而基本相同的函数在C#的Bitmap.FromFile函数中对于上述测试图像都要200多ms,不知为什么,附上Bitmap.FromFile的源码:

public static Image FromFile(string filename, bool useEmbeddedColorManagement)
{
    int num;
    if (!File.Exists(filename))
    {
        IntSecurity.DemandReadFileIO(filename);
        throw new FileNotFoundException(filename);
    }
    filename = Path.GetFullPath(filename);
    IntPtr zero = IntPtr.Zero;
    if (useEmbeddedColorManagement)
    {
        num = SafeNativeMethods.Gdip.GdipLoadImageFromFileICM(filename, out zero);
    }
    else
    {
        num = SafeNativeMethods.Gdip.GdipLoadImageFromFile(filename, out zero);
    }
    if (num != 0)
    {
        throw SafeNativeMethods.Gdip.StatusException(num);
    }
    num = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, zero));
    if (num != 0)
    {
        SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, zero));
        throw SafeNativeMethods.Gdip.StatusException(num);
    }
    Image image = CreateImageObject(zero);
    EnsureSave(image, filename, null);
    return image;
}

 

上述源码中多了一些错误处理的代码,但那些代码明显不会太耗时间。这也是我这里用VB6做测试的原因。

结论2:GetThumbnailImage不适合于做快速的图像缩放预览之类的工作,但是却是选择单开单个图像预览时的好选择。

由以上图片测试结果可以看出,GetThumbnailImage是无法胜任任意大小预览模式的,但是对于大哥图像预览时,大部分大小都只有160*120大小的预览窗口的图像,确实非常合适的。

结论3:C#下的Bitmap或者Image类的GetThumbnailImage函数不适合于做预览工作,原因就是他不如我在VB6下工作的快,特别是对于那些已经内嵌了缩略图的图像。如果是用C#做,我可能会像类似于VB中这样,直接调用GDI+的API函数。

  测试源码下载: http://files.cnblogs.com/Imageshop/ThumbNail.rar

附在的说一下: JPG的EXIF信息中的缩略图格式其实也是JPG格式,这也可以看成为什么JPG内部不一定非要内嵌缩略图的原因,不然缩略图本身格式也是JPG,那缩略图里有要嵌入缩略图....想想吧,会出现什么。

后记: 用了下美图秀秀,在打开8000*6000这样尺寸的JPG进行预览时,初次打开的速度就很快,没感觉到有延迟,并且图像质量还可以,这个的算法过程期待有高人指点下。

***************************作者: laviewpbt   时间: 2013.6.16    联系QQ:  33184777

转载请保留本行信息*************************

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Crimm Imageshop 2.3。

    下载地址:http://files.cnblogs.com/Imageshop/ImageShop.rar     一款体积小,能绿色执行,又功能丰富的图像处...

    用户1138785
  • 【算法随记三】小半径中值模糊的急速实现(16MB图7.5ms实现) + Photoshop中蒙尘和划痕算法解读。

      在本人的博客里,分享了有关中值模糊的O(1)算法,详见:任意半径中值滤波(扩展至百分比滤波器)O(1)时间复杂度算法的原理、实现及效果 ,这里的算法的执行时...

    用户1138785
  • 颜色空间系列2: RGB和CIELAB颜色空间的转换及优化算法

    颜色空间系列代码下载链接:http://files.cnblogs.com/Imageshop/ImageInfo.rar (同文章同步更新)

    用户1138785
  • 为WordPress开启Nginx缩略图功能,七牛从此陌路

    张戈博客曾分享过不少关于云存储的一些经验技巧,对七牛感兴趣或者遇到相关问题的朋友可以看一看以前的相关文章: 七牛&又拍云 CDN 云存储节省 GET 次数的小...

    张戈
  • leecode剑指 Offer 19. 正则表达式匹配

    动态规划能够通过空间换时间,就是将一个问题转移成,子问题。子问题会存储在线性表里面。

    来啦老弟
  • RSA der加密 p12解密以及配合AES使用详解

    在前面的文章中我有说过AES和RSA这两种加密方式,正好在前段时间再项目中有使用到,在这里再把这两种加密方式综合在一起写一下,具体到他们的使用,以及RSA各种加...

    Mr.RisingSun
  • 深度解析 TypeConverter & TypeConverterAttribute (一)

    前言     我们在开发复杂控件的时候不可避免的碰到类型转换TypeConverter,微软给我们提供了很多转换类如ArrayConverter,BaseNu...

    菩提树下的杨过
  • R中如何用ifelse进行数据分组

    数据分组,根据数据分析对象的特征,按照一定的数值指标,把数据分析对象划分为不同的区间部分来研究,以揭示内在的联系和规律性; 在R中,我们常用ifelse函数来进...

    Erin
  • 【LeetCode】(No.014)最长公共前缀

    最长公共前缀指的是字符串数组中所有公共最长的前缀。 如果是空串的话,那么说明前缀就是“” 如果都是以“ ”开头的,那么就是“ ” 然后最长的前缀不会超过最短的字...

    PM小王
  • 基于模拟MRAM神经元和突触的单周期MLP分类器(cs)

    本文利用自旋轨道转矩(SOT)磁阻随机存取存储器(MRAM)器件实现单周期模拟内存计算(IMC)结构中的乙状神经元和二值化突触。首先,我们提出了一种基于模拟SO...

    柴艺

扫码关注云+社区

领取腾讯云代金券