JavaDelphi 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,觉得有点杀鸡用牛刀。所以就想着先实现需求吧,真的分外了再优化吧。在我的Inteli3 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: Intel 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;

Java,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形式,性能丰裕了。
  • 无法不加大画面的(源图比目的图小):要用StretchBlt、StretchDIBits,用SetStretchBltMode必须选HALFTONE格局。性能不可以承受可选DrawDibDraw。
  • 图省事用DrawDibDraw,可能要多耗些资源吧(没规范总括过)。
  • 图形性能要求更高的,啃DirectX、OpenGL、SDL去吗。代码不难,难的是要清楚那么多图形学概念。

相关文章