有单位年会要用照片抽奖,上网搜了几个都不满意,且居然还要收费。自己写一个算了。只是有一点不爽,Delphi 7 在 Windows 7 64位下有问题,不能双击 dpr 文件直接打开项目!

关于性能:

  • 因为总数不大(没超过100个),所以一次性全部载入内存保存,启动速度也不慢,秒开。以流的形式保存,因为可直接使用 TJPEGImage 的 LoadFromStream 方法。如果照片很多,那就要掂量掂量内存占用情况了。实时读取文件的话,同时还要考虑磁盘读写的延时。
  • 图片分辨率对 JPG 的解压、显示的速度影响较大(i3 CPU、B75主板、8G内存):
    4288*2848——耗时 260ms
    1440*956——耗时 109ms
    1156*768——耗时 63ms
    因此,必须限制原始图片的分辨率,宁可放大显示。如果对显示性能要求较高,比如图片切换间隔要求小于100ms(不过短于视觉暂留时间的话就看不见了),必须别想他法。

废话不说,上代码。

 unit main;

 interface

 uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, Menus, Jpeg; type
TMainForm = class(TForm)
MainTimer: TTimer;
PopMenu: TPopupMenu;
MenuClear: TMenuItem;
MainPaint: TPaintBox;
ExitMenu: TMenuItem;
procedure MainTimerTimer(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure MenuClearClick(Sender: TObject);
procedure MainPaintPaint(Sender: TObject);
procedure ExitMenuClick(Sender: TObject);
private
{ Private declarations }
procedure ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
public
{ Public declarations }
end; const
BufferSize=; //缺省照片缓存大小
CoverFileName='COVER.JPG'; //封面图片
WinnerFileName='中奖.txt'; //抽奖结果文件 TextColor=clRed; //显示文字颜色
TextSize=; //显示文字大小
TextFont='华文行楷';//显示文字字体 var
MainForm: TMainForm;
PhotoIndex:integer=; //当前显示的图片索引
PhotoCount:integer=; //图片总数
Names : array of string; //图片名称缓存
Photos : array of TMemoryStream; //JPG文件流缓存
Selected : array of integer; //已中奖图片标志
SelectedCount : integer=; //已中奖数量,如果全部中奖则停止抽奖
Log : TStringList; //中奖记录,存入文本文件 jpg:TJpegImage; //解压JPG用的公用变量
Times:Cardinal; //定时器事件的执行次数 bmpPaint:TBitmap; //作为PaintBox的显示缓存 implementation {$R *.dfm} {
procedure Mosaic(dest:TBitmap; src:TBitmap);
var
i,x,y:Integer;
from:TRect;
bmpwidth,bmpheight:Integer;
const
squ=20;
begin
bmpwidth:=src.Width;
bmpheight:=src.Height; dest.Width:=bmpwidth;
dest.Height:=bmpHeight; for i:=0 to 400 do
begin
Randomize;
x:=Random(bmpwidth div squ);
y:=Random(bmpheight div squ);
from:=Rect(x*squ,y*squ,(x+1)*squ,(y+1)*squ);
dest.Canvas.CopyRect(from,Src.Canvas,from);
end;
end; procedure Alpha(bitmap:TBitmap; jpg:TJPEGImage);
var
BlendFunc: TBlendFunction;
bit:TBitmap;
begin
bit := TBitMap.Create;
try
jpg.DIBNeeded;
bit.Assign(jpg);
BlendFunc.BlendOp := AC_SRC_OVER;
BlendFunc.BlendFlags := 0;
BlendFunc.AlphaFormat := 0;
BlendFunc.SourceConstantAlpha := 127;
windows.AlphaBlend(bitmap.Canvas.Handle, 0, 0, bit.Width, bit.Height,
bit.Canvas.Handle, 0, 0, bit.Width, bit.Height,
BlendFunc);
finally
bit.Free;
end;
end;
} //源图等比缩放后填充目标图片,width、height指定可用显示区域的大小
procedure ZoomFill(dest:TBitMap; src:TGraphic; width,Height:integer);
var
ZoomX,ZoomY,Zoom:double;
begin
zoomY:= Height / src.Height;
zoomX:= Width / src.Width;
// zoom 为 min(zoomX,zoomY)
if (ZoomX<ZoomY) then
zoom:= zoomX
else
zoom:=zoomY;
dest.Width:= trunc(src.width*zoom);
dest.Height:= trunc(src.Height*zoom);
dest.Canvas.StretchDraw(rect(, , dest.Width, dest.Height), src);
end; // 显示图片,name指定了文本(固定居左、上下居中位置)
procedure TMainForm.ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
begin
if not src.Empty then
begin
ZoomFill(bmpPaint,src,screen.Width,screen.Height);
if length(name)> then
begin
bmpPaint.Canvas.Brush.Style := bsClear;
bmpPaint.Canvas.TextOut(
,
(bmpPaint.Height-bmpPaint.Canvas.textheight(name)) div ,
name);
end;
paint.Repaint;
end;
end; //关闭 Form 时释放资源
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
if MainTimer.Enabled then
MainTimer.Enabled:=false; bmpPaint.Free; Log.SaveToFile(WinnerFileName);
Log.Free;
jpg.Free; for i:= to photocount- do
Photos[i].Free;
end; //创建 Form 时初始化资源
procedure TMainForm.FormCreate(Sender: TObject);
var
SearchRec:TSearchRec;
found:integer;
i:integer;
begin
// 开启双缓冲,减少屏幕闪烁
if not Self.doubleBuffered then
Self.doubleBuffered:=true; //初始化缓冲区
setlength(Names,BufferSize);
setlength(Photos,BufferSize);
setlength(Selected,BufferSize); Log:=TStringList.Create;
jpg:=TJpegImage.Create; bmpPaint:=tBitmap.create;
BmpPaint.pixelformat := pf24bit;
bmpPaint.Canvas.Font.Size:=textSize;
bmpPaint.Canvas.Font.Color:=textColor;
bmpPaint.Canvas.Font.Name:=TextFont; // 窗口全屏
Self.BorderStyle := bsNone;
Self.Left := ;
Self.Top := ;
Self.Width := Screen.Width;
Self.Height := Screen.Height; // 载入封面图片
try
jpg.LoadFromFile(coverfilename);
jpg.DIBNeeded;
except
end;
ShowPhoto(MainPaint, jpg, ''); // 载入 data 目录下的所有JPG文件
found:=FindFirst('data\*.jpg',faAnyFile,SearchRec);
try
while found= do
begin
if (SearchRec.Name<>'.') and (SearchRec.Name<>'..')
and (SearchRec.Attr<>faDirectory) then
begin
if (PhotoCount>=length(Names)) then //内存缓冲长度不足
begin
setlength(Names,length(Names)*);
setlength(Photos,length(Names));
setlength(Selected,length(Names));
end;
Names[PhotoCount]:= ChangeFileExt(SearchRec.Name,'');
Photos[PhotoCount]:=TMemoryStream.Create;
Photos[PhotoCount].LoadFromFile('data\'+ SearchRec.Name);
inc(PhotoCount);
end;
found:=FindNext(SearchRec);
end;
finally
FindClose(SearchRec);
end; //载入中奖纪录
if fileexists(WinnerFileName) then
log.LoadFromFile(WinnerFileName);
if (log.Count>) then //标记已中奖者
begin
for i:= to photoCount- do
if log.IndexOf(names[i])>= then
begin
Selected[i]:=;
inc(selectedCount);
end;
end; end; //计时器事件
procedure TMainForm.MainTimerTimer(Sender: TObject);
var
s:TMemoryStream;
begin
repeat
Randomize;
PhotoIndex:=random(photocount);
until (Selected[photoIndex]<=); //跳过已中奖的图片
s:= Photos[PhotoIndex];
jpg.LoadFromStream(s);
s.Position:=; //这句必不可少。否则再读时不会报错,jpg.Empty不为空,但长度宽度均为0。
showPhoto(MainPaint,jpg,Names[PhotoIndex]);
inc(times);
//逐渐加快图片滚动速度
if (times>) then
begin
if MainTimer.Interval> then
MainTimer.Interval:=;
end
else if times> then
maintimer.Interval:=
else if times> then
Maintimer.Interval:=
else
MainTimer.Interval:=;
end; //按键处理
procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#) then //Esc
begin
MainTimer.Enabled:=false;
showmessage(Log.Text);
close;
end
else if (Key=' ') or (Key=#) then
begin
if MainTimer.Enabled then //要停止滚动
begin
MainTimer.Enabled:=false;
inc(SelectedCount);
Selected[PhotoIndex]:=; //设置中奖标记
Log.Append(Names[PhotoIndex]);
Log.SaveToFile(WinnerFileName);
end
else
begin //要开始滚动
if SelectedCount<PhotoCount then //还有未中奖
begin
times:=;
MainTimer.Enabled:=true;
end
else
showmessage('全部人员均已抽中!');
end;
end;
end; //清除中奖纪录
procedure TMainForm.MenuClearClick(Sender: TObject);
var
i:integer;
begin
if MessageDlg('真的要清除中奖记录么?',
mtConfirmation, [mbYes, mbNo], ) = mrYes then
begin
Log.Clear;
SelectedCount:=;
for i:= to PhotoCount- do
selected[i]:=;
if fileexists(WinnerFileName) then
deletefile(WinnerFileName);
end;
end; //重绘 TPaintBox 事件
procedure TMainForm.MainPaintPaint(Sender: TObject);
begin
with MainPaint.Canvas do
begin
pen.mode := pmcopy;
brush.style := bssolid;
copymode := srccopy;
draw(
(MainPaint.Width-bmpPaint.Width) div , //左右居中
(MainPaint.Height-bmpPaint.Height) div , //上下居中
bmpPaint);
end;
end; procedure TMainForm.ExitMenuClick(Sender: TObject);
begin
close;
end; end.

可执行程序下载

Delphi 实现照片抽奖-原创的更多相关文章

  1. 《zw版·delphi与Halcon系列原创教程》THOperatorSetX版hello,zw

    <zw版·delphi与Halcon系列原创教程>THOperatorSetX版hello,zw 下面介绍v3版的hello,zw. Halcon两大核心控件,THImagex.THOpe ...

  2. 《zw版·delphi与halcon系列原创教程》zw版_THOperatorSetX控件函数列表 v11中文增强版

    <zw版·delphi与halcon系列原创教程>zw版_THOperatorSetX控件函数列表v11中文增强版 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就 ...

  3. 《zw版·delphi与halcon系列原创教程》zw版_THImagex控件函数列表

    <zw版·delphi与halcon系列原创教程>zw版_THImagex控件函数列表 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就要7w多行,但核心控件就是两 ...

  4. 《zw版·delphi与halcon系列原创教程》hello,zw

    <zw版·delphi与halcon系列原创教程>hello,zw 按惯例,第一个程序是‘hello’ 毕竟,Halcon是专业的图像库,所以我们就不用纯文本版的,来一个专业版.Halco ...

  5. JS原生实现照片抽奖

    HTML表格标记实现九宫格,放入九张图片.利用CSS的滤镜属性控制图片的透明度.Javascript实现抽奖和中奖. 可以做为教师上课,随机抽取回答问题的同学,使学生感受到随机的公平性,简单有趣! 点 ...

  6. Delphi中的RectTracker - 原创

    本文算是副产品,正品是利用FFmpeg从任意视频中生成GIF片段的小程序,写完了就发. 因为要对视频画面进行框选,再生成GIF,所以得有个框选的控件,可Delphi里没有啊,只好自己写一个了. 声明 ...

  7. Delphi 中的 RectTracker - 原创

    本文算是副产品,正品是利用 FFmpeg 从任意视频中生成GIF片段的小程序,写完了就发. V2G 正品已出炉,虽然不大像样,但好歹是能用,请见:用 Delphi 7 实现基于 FFMS2 的视频转 ...

  8. 【《zw版·Halcon与delphi系列原创教程》Halcon图层与常用绘图函数

    [<zw版·Halcon与delphi系列原创教程>Halcon图层与常用绘图函数 Halcon的绘图函数,与传统编程vb.c.delphi语言完全不同,     传统编程语言,甚至cad ...

  9. 《zw版·ddelphi与halcon系列原创教程》Halcon的短板与delphi

    [<zw版·delphi与Halcon系列原创教程>Halcon的短板与delphi 看过<delphi与Halcon系列>blog的网友都知道,笔者对Halcon一直是非常推 ...

随机推荐

  1. JNI由浅入深_6_简单对象的应用

    1.声明native方法 public class ComplexObject { /** * 返回一个对象数组 * @param val * @return */ public native Per ...

  2. 梯度下降法&牛顿法

    梯度下降法 在机器学习任务中,需要最小化损失函数\(L(\theta)\),其中\(\theta\)是要求解的模型参数.梯度下降法是一种迭代方法,用到损失函数的一阶泰勒展开.选取初值\(\theta ...

  3. Oracle特殊查询 行列倒转 分页

    --查询工资最高的前三名 (分页的感觉)select * from(select * from emp order by sal desc) twhere rownum <=3--查询工资最高的 ...

  4. 2019年,iOS开发的你不可或缺的进阶之路!

    序言 我相信很多人都在说,iOS行业不好了,iOS现在行情越来越难了,失业的人比找工作的人还要多.失业即相当于转行,跳槽即相当于降低自己的身价.那么做iOS开发的你,你是否在时刻准备着跳槽或者转行了. ...

  5. iOS双滑块选择器

    iOS双滑块选择器 <SDRangeSliderView> https://github.com/qddnovo/SDRangeSliderView 实现了通用性和便利性 今天是个好日子

  6. Model验证简单易懂

    public bool UserSex { get; set; } //定义名字 [Display(Name = "年龄")] [Range(0, 150, ErrorMessag ...

  7. vue项目获取当前地址栏参数(非路由传参)

    项目中遇到一个需求,就是另一个管理系统带参直接单纯的跳转跳转到vue pc项目中的某个页面,后再初始化查询数据,参数以地址栏的形式传入 管理系统:打开新地址地址 let obj = { id: 21, ...

  8. ABAP术语-Update Module

    Update Module 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/20/1114178.html Part of an update ...

  9. MySQL----MySQL数据库入门----第五章 多表操作

    5.1 外键 比如说有两个数据表,分别是学生信息表student和年级表grade.在student表中有存储学生年级的字段gid(外键),在grade表也有存储学生年级的字段id(主键),stude ...

  10. 使用babel插件集

    1).打开配置文件".babelrc",配置插件集,代码如下: { "presets":["latest"] } 2).安装babel插件集 ...