Delphi 7中对StretchBlt, StretchDIBits, DrawDibDraw, BitBlt 的属性测试 – 原创

自己的天哪,上一篇博文是2年前的作业了。看来又虚度了2年生活,继续攻读。。。
本文算是副产品,正品是使用FFmpeg从随机视频中生成GIF片段的小程序,等写完了再发。不为其余,只是为了给外甥做动图,且看不惯这种工具也要收费!

声明

正文是首先看到了求比Stretchblt方法更快的缩放算法的帖子,请参考其中署名为“张辉明”的复原。我做了优化和有些校订,但DrawDibDraw部分的调用是原文照录的。(其实上文就是本身Bing了DrawDibDraw时搜到的。)

何以要测试 StretchBlt, StretchDIBits, DrawDibDraw 的特性

因为摄像回看须要很高的突显质量,解码占了广大总括量,留给突显的时辰不多,能优化则优化吧。

实际上现在的CPU跑个摄像播放已经绰绰有余了,GPU压根就不必用。即使是用Delphi自带的TImage控件,用Bitmap往里填也得以满意普通播放须求了。即使时光倒流到10年前,那可正是得去讨论DirectX、OpenGL了。可惜关于那哥俩,半数以上都是C、C++的资源,我啃了半天SDL,觉得有点杀鸡用牛刀。所以就想着先落成须要吧,真的更加了再优化吧。在自身的AMDi3 3220上,用StretchDIBits播放视频时最多也就跑了22%。

干什么还抱着Delphi不放?

  1. 性价比第一
    敢问品质、便捷、体积俱佳的Windows开发环境,何人敢和Delphi比?C#,Java是优质,可为了一个小功效就跑它个虚拟机,实在划不来啊。C++倒是够sharp,可学习进度太痛心了,代码还不不难写。
  2. 全能
    都说Python好,可我眼拙,实在看不出来好在哪个地方,局限性太大。唯一的好处是能让新手迅速上手编程,还有一个便宜是能让你忘掉统计机是怎么运作的!
  3. 怀旧
    十几年前自学的事物,从Delphi
    3开首用,有心思了。只要Windows不停歇对32位程序的辅助,我就会平素用下来。(关于那或多或少,我要狠狠鄙视Apple一下。)
  4. Delphi 7是经典
    和Visual
    Studio、水果一样,当年Borland的出品也有大小年,逢单的版本就是平稳一些。尽管轮子有时候得从头初步造,然而“知其所以然”是乐在其中的事,相信自己!

测试结果

一旦只关心结果,或者对Delphi不屑,那你就无须往下看了,我先提交结果吗。为你节约点时间。严俊意义上说,BitBlt不属于其余哥仨的阵营,因为不用缩放,所以速度自然快了。放在此处相比较,就当是个Baseline吧。

  1. DrawDibDraw.aspx)最快(1ms级别)。
    不到StretchBlt和StretchDIBits的一半,且不需求用SetStretchBltMode.aspx)设置哪些缩放格局,画质看不出分别。
  2. StretchBlt.aspx)和StretchDIBits.aspx)难分伯仲。
    用了色彩拟合方式(HALFTONE)的话会大大增加总括量,耗时4倍,比DrawDibDraw慢1个数据级。提出减少图像时得以用COLORONCOLOR方式,肉眼看不出不相同,但可以比HALFTONE格局提速4倍!
API COLORONCOLOR HALFTONE
BitBlt 400 400
DrawDibDraw 1125 1125
StretchBlt 3000 11406
StretchDIBits 3203 11576
  • 测试用机:CPU: AMD i3 3220,内存: 8G DDRIII 1333,显卡: 英特尔 Radeon
    HD 7700 (对测试结果没影响啊),Windows 10专业版
  • 测试次数:1000次
  • 时间单位:millisecond(微秒)
  • COLORONCOLOR:删除不必要的点。
    那是SetStretchBltMode的参数,指定目标设备(区域)的缩放情势。在用StretchDIBits和StretchBlt时务必得设置一个缩放形式,不然,嘿嘿,惨不忍睹。官方认证是:“Deletes
    the pixels. This mode deletes all eliminated lines of pixels without
    trying to preserve their
    information.”,汉语意思大致就是:删除不需求的像素点。该形式删除所有无用的点阵,这一个点的所有信息都反对保留。
    参见SetStretchBltMode.aspx)。
  • HALFTONE:将源区域的颜色溶入目的区域中去。
    功能同上。官方证实是:“Maps pixels from the source rectangle into
    blocks of pixels in the destination rectangle. The average color
    over the destination block of pixels approximates the color of the
    source
    pixels.”中文大致意思是:将源矩形区域的像素点新闻拟合到目的区域周边的多少个像素块中。目标区域七个像素块的水彩值会进行平均,以便最大程度地类似源像素的情调。参见SetStretchBltMode.aspx)。

源码

界面

就放了多少个按钮而已,名称末尾为C的代表用了COLORONCOLOR格局,为H的意味用了HALFTONE形式。还有一个提姆age控件。

常量

FileName定义了Bmp图片文件名,Count定义了测试循环的次数。

FileName='1.bmp';
Count=1000;
FontSize=20;

BMP文件读取

因为StretchBlt和BitBlt只须要提供源HDC,不须要用tagBITMAPINFO和原始RGB数据区作为参数,所以一向用了TBitmap控件载入图片文件。

procedure TMainForm.StretchBltDisplay;
var
  bmp : TBitmap ;
  i : Integer ;
  Start : DWORD ;
begin
  Bmp:= TBitmap.Create ;
  bmp.LoadFromFile(FileName);

  Start := GetTickCount ;
  for i := 1 to count do
  begin
    StretchBlt(image1.Canvas.Handle, 0, 0, image1.ClientWidth, image1.ClientHeight,
              bmp.Canvas.Handle, 0,0,bmp.Width,bmp.Height, SRCCOPY);
    image1.Canvas.TextOut(10,10,inttostr(i));
    image1.Refresh;
  end;
  MainForm.Caption := IntToStr(GetTickCount - Start);

  bmp.Free ;
end;

DrawDibDraw和DrawDibDraw都亟待运用BMP原始音信做参数,所以只好写了个LoadBmp从文件中读取数据。
因为要把原有音信带出来,所以带了var前缀。

procedure LoadBmp(bmpFile: String; var bmpinfo:TBitmapInfo; var pBmpData:Pointer);
var
  bmf: TBitmapFileHeader;
  imageSize: LongWord;
  Stream: TFileStream;
begin
   try
    Stream:= TFileStream.Create(bmpFile, fmOpenRead or fmShareDenyWrite);
    Stream.Read(bmf, sizeof(Bmf));
    Stream.Read(bmpinfo, sizeof(bmpinfo));
    imageSize:= bmf.bfSize-bmf.bfOffBits;
    stream.Seek(bmf.bfOffBits,0);

    FreeMem(pBmpData);
    GetMem(pBmpData, imageSize);

    Stream.Read(pBmpData^, ImageSize);
  finally
    FreeAndNil(Stream);
  end;
end;

关于var前缀

一开始认为,用指针就可以在函数内给外部的指针分配内存并传出结果了。但骨子里不对,外面的指针还一向是nil。必须带上var前缀才行(指针的指针)。

关于VFW

DrawDibDraw是VFW(Video for
Windows
.aspx))中的API,关于DrawDibDraw的用法可以参考园子里的DrawDibDraw函数的行使办法。封装文件VFW.pas来自一篇《delphi视频头编程vfw》,出处已不可考,被署名TomNuydens的修改过。

全体源码

敲定和指出

  • 单单裁减画面的(源图一定比目的图大):StretchBlt、StretchDIBits随便用,先用SetStretchBltMode选COLORONCOLOR格局,性能充裕了。
  • C++,务必加大画面的(源图比目的图小):要用StretchBlt、StretchDIBits,用SetStretchBltMode必须选HALFTONE情势。质量无法承受可选DrawDibDraw。
  • 图省事用DrawDibDraw,可能要多耗些资源吧(没规范统计过)。
  • 图表品质要求更高的,啃DirectX、OpenGL、SDL去吗。代码不难,难的是要领悟那么多图形学概念。