照片抽奖程序-原创

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

关于性能:

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

废话不说,上代码。

  1 unit main;
  2
  3 interface
  4
  5 uses
  6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7   Dialogs, StdCtrls, ExtCtrls, ComCtrls, Menus, Jpeg;
  8
  9 type
 10   TMainForm = class(TForm)
 11     MainTimer: TTimer;
 12     PopMenu: TPopupMenu;
 13     MenuClear: TMenuItem;
 14     MainPaint: TPaintBox;
 15     ExitMenu: TMenuItem;
 16     procedure MainTimerTimer(Sender: TObject);
 17     procedure FormKeyPress(Sender: TObject; var Key: Char);
 18     procedure FormClose(Sender: TObject; var Action: TCloseAction);
 19     procedure FormCreate(Sender: TObject);
 20     procedure MenuClearClick(Sender: TObject);
 21     procedure MainPaintPaint(Sender: TObject);
 22     procedure ExitMenuClick(Sender: TObject);
 23   private
 24     { Private declarations }
 25     procedure ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
 26   public
 27     { Public declarations }
 28   end;
 29
 30 const
 31   BufferSize=64;              //缺省照片缓存大小
 32   CoverFileName=‘COVER.JPG‘;  //封面图片
 33   WinnerFileName=‘中奖.txt‘;  //抽奖结果文件
 34
 35   TextColor=clRed;    //显示文字颜色
 36   TextSize=72;        //显示文字大小
 37   TextFont=‘华文行楷‘;//显示文字字体
 38
 39 var
 40   MainForm: TMainForm;
 41   PhotoIndex:integer=0;     //当前显示的图片索引
 42   PhotoCount:integer=0;     //图片总数
 43   Names : array of string;  //图片名称缓存
 44   Photos : array of TMemoryStream; //JPG文件流缓存
 45   Selected : array of integer;  //已中奖图片标志
 46   SelectedCount : integer=0;    //已中奖数量,如果全部中奖则停止抽奖
 47   Log : TStringList;  //中奖记录,存入文本文件
 48
 49   jpg:TJpegImage;   //解压JPG用的公用变量
 50   Times:Cardinal;   //定时器事件的执行次数
 51
 52   bmpPaint:TBitmap; //作为PaintBox的显示缓存
 53
 54 implementation
 55
 56 {$R *.dfm}
 57
 58 {
 59 procedure Mosaic(dest:TBitmap; src:TBitmap);
 60 var
 61   i,x,y:Integer;
 62   from:TRect;
 63   bmpwidth,bmpheight:Integer;
 64 const
 65   squ=20;
 66 begin
 67   bmpwidth:=src.Width;
 68   bmpheight:=src.Height;
 69
 70   dest.Width:=bmpwidth;
 71   dest.Height:=bmpHeight;
 72
 73   for i:=0 to 400 do
 74   begin
 75     Randomize;
 76     x:=Random(bmpwidth div squ);
 77     y:=Random(bmpheight div squ);
 78     from:=Rect(x*squ,y*squ,(x+1)*squ,(y+1)*squ);
 79     dest.Canvas.CopyRect(from,Src.Canvas,from);
 80   end;
 81 end;
 82
 83 procedure Alpha(bitmap:TBitmap; jpg:TJPEGImage);
 84 var
 85   BlendFunc: TBlendFunction;
 86   bit:TBitmap;
 87 begin
 88   bit := TBitMap.Create;
 89   try
 90     jpg.DIBNeeded;
 91     bit.Assign(jpg);
 92     BlendFunc.BlendOp := AC_SRC_OVER;
 93     BlendFunc.BlendFlags := 0;
 94     BlendFunc.AlphaFormat := 0;
 95     BlendFunc.SourceConstantAlpha := 127;
 96     windows.AlphaBlend(bitmap.Canvas.Handle, 0, 0, bit.Width, bit.Height,
 97                        bit.Canvas.Handle,  0, 0, bit.Width, bit.Height,
 98                        BlendFunc);
 99   finally
100     bit.Free;
101   end;
102 end;
103 }
104
105 //源图等比缩放后填充目标图片,width、height指定可用显示区域的大小
106 procedure ZoomFill(dest:TBitMap; src:TGraphic; width,Height:integer);
107 var
108   ZoomX,ZoomY,Zoom:double;
109 begin
110   zoomY:= Height / src.Height;
111   zoomX:= Width / src.Width;
112   // zoom 为 min(zoomX,zoomY)
113   if (ZoomX<ZoomY) then
114     zoom:= zoomX
115   else
116     zoom:=zoomY;
117   dest.Width:= trunc(src.width*zoom);
118   dest.Height:= trunc(src.Height*zoom);
119   dest.Canvas.StretchDraw(rect(0, 0, dest.Width, dest.Height), src);
120 end;
121
122 // 显示图片,name指定了文本(固定居左、上下居中位置)
123 procedure TMainForm.ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
124 begin
125   if not src.Empty then
126   begin
127     ZoomFill(bmpPaint,src,screen.Width,screen.Height);
128     if length(name)>0 then
129     begin
130       bmpPaint.Canvas.Brush.Style := bsClear;
131       bmpPaint.Canvas.TextOut(
132         10,
133         (bmpPaint.Height-bmpPaint.Canvas.textheight(name)) div 2,
134         name);
135     end;
136     paint.Repaint;
137   end;
138 end;
139
140 //关闭 Form 时释放资源
141 procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
142 var
143   i:integer;
144 begin
145   if MainTimer.Enabled then
146     MainTimer.Enabled:=false;
147
148   bmpPaint.Free;
149
150   Log.SaveToFile(WinnerFileName);
151   Log.Free;
152   jpg.Free;
153
154   for i:=0 to photocount-1 do
155     Photos[i].Free;
156 end;
157
158 //创建 Form 时初始化资源
159 procedure TMainForm.FormCreate(Sender: TObject);
160 var
161   SearchRec:TSearchRec;
162   found:integer;
163   i:integer;
164 begin
165   // 开启双缓冲,减少屏幕闪烁
166   if not Self.doubleBuffered then
167     Self.doubleBuffered:=true;
168
169   //初始化缓冲区
170   setlength(Names,BufferSize);
171   setlength(Photos,BufferSize);
172   setlength(Selected,BufferSize);
173
174   Log:=TStringList.Create;
175   jpg:=TJpegImage.Create;
176
177   bmpPaint:=tBitmap.create;
178   BmpPaint.pixelformat := pf24bit;
179   bmpPaint.Canvas.Font.Size:=textSize;
180   bmpPaint.Canvas.Font.Color:=textColor;
181   bmpPaint.Canvas.Font.Name:=TextFont;
182
183   // 窗口全屏
184   Self.BorderStyle := bsNone;
185   Self.Left := 0;
186   Self.Top := 0;
187   Self.Width := Screen.Width;
188   Self.Height := Screen.Height;
189
190   // 载入封面图片
191   try
192     jpg.LoadFromFile(coverfilename);
193     jpg.DIBNeeded;
194   except
195   end;
196   ShowPhoto(MainPaint, jpg, ‘‘);
197
198   // 载入 data 目录下的所有JPG文件
199   found:=FindFirst(‘data\*.jpg‘,faAnyFile,SearchRec);
200   try
201     while found=0 do
202     begin
203       if (SearchRec.Name<>‘.‘)  and (SearchRec.Name<>‘..‘)
204            and (SearchRec.Attr<>faDirectory) then
205       begin
206         if (PhotoCount>=length(Names)) then  //内存缓冲长度不足
207         begin
208           setlength(Names,length(Names)*2);
209           setlength(Photos,length(Names));
210           setlength(Selected,length(Names));
211         end;
212         Names[PhotoCount]:= ChangeFileExt(SearchRec.Name,‘‘);
213         Photos[PhotoCount]:=TMemoryStream.Create;
214         Photos[PhotoCount].LoadFromFile(‘data\‘+ SearchRec.Name);
215         inc(PhotoCount);
216       end;
217       found:=FindNext(SearchRec);
218     end;
219   finally
220     FindClose(SearchRec);
221   end;
222
223   //载入中奖纪录
224   if fileexists(WinnerFileName) then
225     log.LoadFromFile(WinnerFileName);
226   if (log.Count>0) then //标记已中奖者
227   begin
228     for i:=0 to photoCount-1 do
229       if log.IndexOf(names[i])>=0 then
230       begin
231         Selected[i]:=1;
232         inc(selectedCount);
233       end;
234   end;
235
236 end;
237
238 //计时器事件
239 procedure TMainForm.MainTimerTimer(Sender: TObject);
240 var
241   s:TMemoryStream;
242 begin
243   repeat
244     Randomize;
245     PhotoIndex:=random(photocount);
246   until (Selected[photoIndex]<=0); //跳过已中奖的图片
247   s:= Photos[PhotoIndex];
248   jpg.LoadFromStream(s);
249   s.Position:=0;  //这句必不可少。否则再读时不会报错,jpg.Empty不为空,但长度宽度均为0。
250   showPhoto(MainPaint,jpg,Names[PhotoIndex]);
251   inc(times);
252   //逐渐加快图片滚动速度
253   if (times>16) then
254   begin
255     if MainTimer.Interval>125 then
256       MainTimer.Interval:=125;
257   end
258   else if times>8 then
259     maintimer.Interval:=250
260   else if times>3 then
261     Maintimer.Interval:=500
262   else
263     MainTimer.Interval:=800;
264 end;
265
266 //按键处理
267 procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
268 begin
269   if (Key=#27) then //Esc
270   begin
271     MainTimer.Enabled:=false;
272     showmessage(Log.Text);
273     close;
274   end
275   else  if (Key=‘ ‘) or (Key=#13) then
276   begin
277     if MainTimer.Enabled then //要停止滚动
278     begin
279       MainTimer.Enabled:=false;
280       inc(SelectedCount);
281       Selected[PhotoIndex]:=1;  //设置中奖标记
282       Log.Append(Names[PhotoIndex]);
283       Log.SaveToFile(WinnerFileName);
284     end
285     else
286     begin //要开始滚动
287       if SelectedCount<PhotoCount then  //还有未中奖
288       begin
289         times:=0;
290         MainTimer.Enabled:=true;
291       end
292       else
293         showmessage(‘全部人员均已抽中!‘);
294     end;
295   end;
296 end;
297
298 //清除中奖纪录
299 procedure TMainForm.MenuClearClick(Sender: TObject);
300 var
301   i:integer;
302 begin
303   if MessageDlg(‘真的要清除中奖记录么?‘,
304     mtConfirmation, [mbYes, mbNo], 0) = mrYes then
305   begin
306     Log.Clear;
307     SelectedCount:=0;
308     for i:=0 to PhotoCount-1 do
309       selected[i]:=0;
310     if fileexists(WinnerFileName) then
311       deletefile(WinnerFileName);
312   end;
313 end;
314
315 //重绘 TPaintBox 事件
316 procedure TMainForm.MainPaintPaint(Sender: TObject);
317 begin
318   with MainPaint.Canvas do
319   begin
320     pen.mode := pmcopy;
321     brush.style := bssolid;
322     copymode := srccopy;
323     draw(
324       (MainPaint.Width-bmpPaint.Width) div 2,   //左右居中
325       (MainPaint.Height-bmpPaint.Height) div 2, //上下居中
326       bmpPaint);
327   end;
328 end;
329
330 procedure TMainForm.ExitMenuClick(Sender: TObject);
331 begin
332   close;
333 end;
334
335 end.

可执行程序下载

时间: 2024-10-29 12:38:33

照片抽奖程序-原创的相关文章

java版转盘抽奖程序

最近抽空弄了个转盘抽奖程序,属于半原创,是基于网络上分享的资源二次开发的. 由于未知最初出处,也不知本人搜寻的资源是属于第几手,因此暂无法给出转载链接. ---------- 如果其他人要转载本文,请加上本文链接,毕竟这算本人二次开发的小作品. --------- 下载地址: http://yunpan.cn/cjG2P5kBfvQ6H  提取码 ff7d --------- 本程序 效果如图所示:

jQuery实现圆盘活动抽奖程序效果

<script type="text/javascript" src="jquery-1.7.2.min.js"></script> <script type="text/javascript" src="jQueryRotate.2.2.js"></script> <script type="text/javascript" src="jqu

十分简单的年会抽奖程序

年会那个抽奖程序崩溃实在令人印象太深刻了,所以自己弄了一个简单版本的... data=[] #从数据库或者文件获取员工抽奖id,放到data iNum= raw_input("please input the numbers:\n")#抽几个人 # method= raw_input("please input the method:\n")#做所谓奇偶数抽奖,没意义 allwindata=[] while iNum: windata=[] for i in ran

java模拟一个抽奖程序

今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文本框 JTextField * 按钮  JButton 还涉及到线程Thread 先看效果图: 但是这里留一个问题?就是去除重复数字(可以自己先实现,后期我会上传的) 下面看看代码,代码中有注释,不懂留言: package thread.test1; import java.awt.BorderLa

javascript实现抽奖程序

昨天开年会的时候看到一个段子说唯品会年会抽奖,结果大奖都被写抽奖程序的部门得了,CTO现场review代码. 简单想了一下抽奖程序的实现,花了十几分钟写了一下,主要用到的知识有数组添加删除,以及ES5 数组新增的indexOf,filter方法, 为了刷新页面后仍能保存已中奖记录,用了localStorage存盘. 刚开始是用随机数直接取编号,发现要剔除已中奖的人很麻烦,如果重复要递归调用,如果中奖的人太多到最后随机数取到已中奖的人概率太大,所以换用两个数组实现,一个记录已中奖的号码,一个记录未

使用jQuery+PHP+Mysql实现抽奖程序

抽奖程序在实际生活中广泛运用,由于应用场景不同抽奖的方式也是多种多样的.本文将采用实例讲解如何利用jQuery+PHP+Mysql实现类似电视中常见的一个简单的抽奖程序. 查看演示 本例中的抽奖程序要实现从海量手机号码中一次随机抽取一个号码作为中奖号码,可以多次抽奖,被抽中的号码将不会被再次抽中.抽奖流程:点击“开始”按钮后,程序获取号码信息,滚动显示号码,当点击“停止”按钮后,号码停止滚动,这时显示的号码即为中奖号码,可以点击“开始”按钮继续抽奖. HTML <div id="roll&

相同概率的抽奖程序另类实现——使用数据库,无需数学原理

抽奖,是很多企业.聚会的常见玩乐形式,光彩绚丽的抽奖屏幕背后,是计算程序+抽奖用户信息.程序=算法+数据结构. 好,说抽奖程序的的实现吧.这个实现一般需要应用数学原理.而本文的方法是我在参加一次婚礼的抽奖体验后突然想到的,一种比较简单.无需数学原理的方法. 功能:能按照相同概率,从用户集合中抽出随机的部分用户集合作为中奖者.抽奖可以进行多次,对已中奖的用户不会重复抽取. 使用技术: 1.SqlServer数据库,使用NewID()作为select随机筛选函数 2.sql随机函数 3.为了快速方便

JavaScript简单抽奖程序的实现及代码

JavaScript简单抽奖程序的实现及代码 1.需求说明 某公司年终抽奖,需要有如下功能 1)可以根据实际情况设置到场人数的最大值 2) 点击"开始",大屏幕滚动,点击"停止",获奖者的编号出现在大屏幕上 3)在界面里显示全部奖项获奖人编号 4)不重复获奖 5)不会因为输入错误而导致抽奖结果异常. 2.代码呈上 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">

幸运大转盘-jQuery+PHP实现的抽奖程序

原文  https://www.helloweba.com/view-blog-215.html 准备工作 首先要准备素材,抽奖的界面用到两张图片,圆盘图片和指针图片,实际应用中可以根据不同的需求制作不同的圆盘图片. 接着制作html页面,实例中我们在body中加入如下代码: <div class="demo">     <div id="disk"></div>     <div id="start"&