圖片處理 应用服务器数据结构企业应用网络应用PowerBuilder
一、//网友PB(HIS开发 )友情提供 PB_SOFT 发布http://www.codesky.net
源码空间
//读取保存图片
string ls_pathname, ls_filename
integer li_value,li_FileNum,loops,i
long ll_fileLength,bytes_read,new_pos
blob b, tot_b
Blob gb_photo
INSERT INTO PJ_TP(AA) VALUES ('1') USING SQLCA;
COMMIT USING SQLCA;
li_value = GetFileOpenName("选择照片", &
+ ls_pathname, ls_filename, "jpg","Jpg Files (*.jpg),*.jpg")
IF li_value = 1 THEN
// Set a wait cursor
SetPointer(HourGlass!)
// Get the file length, and open the file
ll_fileLength= FileLength(ls_filename)
li_FileNum = FileOpen(ls_filename, &
StreamMode!, Read!, LockRead!)
// Determine how many times to call FileRead
IF ll_filelength > 32765 THEN
IF Mod(ll_filelength, 32765) = 0 THEN
loops =ll_filelength/32765
ELSE
loops = (ll_filelength/32765) + 1
END IF
ELSE
loops = 1
END IF
// Read the file
new_pos = 1
FOR i = 1 to loops
bytes_read = FileRead(li_FileNum, b)
tot_b = tot_b + b
//
IF i=1 then
st_1.text=string(tot_b)
end if
//
NEXT
FileClose(li_FileNum)
gb_photo=tot_b
UPDATEBLOB PJ_TP SET photo=:gb_photo WHERE AA='1' USing sqlca;
IF Sqlca.SQLNRows > 0 THEN
COMMIT USING SQLCA;
END IF
P_1.setpicture(gb_photo)
st_1.text=string(len(gb_photo))
Elseif li_value=-1 then
MessageBox("选择照片","打开文件错误!")
End If
//从表里读取图片
Blob gb_photo
SELECTBLOB photo INTO :gb_photo FROM PJ_TP where AA='1' Using SQLCA;
st_1.text=string(len(gb_photo))
P_1.setpicture(gb_photo)
**********************************************************************************************************
二、前言:在数据库的开发过程中,经常需要在数据库中存储一些备注信息,而这些备注信息的内容一般较大,格式多样-如有可能是语音文件、视频文件、 图片文件、文本文件等,怎样在PB中实现这些格式不同的备注文件的存取及预览,一直是PB开发人员比较关心的一个问题,本文系统的介绍了三种存取备注二进 制信息的方法。 对备注二进制信息的存储可以采用以下三种方式;
方法一:文件保存在固定的路径下,数据库中存取文件路径和名称
方法二:数据库中用blob类型或者varbinary类型字段存储备注文件
方法三:在本地用OLE存储结构存储备注文件
1、OLE的基本概念
OLE是Object Linking Embedding(对象链结与嵌入)的缩写,它可以使windows应用程序共享数据和程序。
2、OLE控件
在PB中OLE控件是一个OLE对象的包容器,可以使用服务器应用程序提供的功能和命令来编辑对象,也可以使用自动化OLE交互,在程序中激活对象和向服务器应用程序发送命令;在PB 的window画板中的OLE控件允许用户从多个应用程序嵌入和链结组件
2.1建立和设置OLE控件
从window画板中选择OLE控件插入window。
当建立一个OLE控件并且插入一个对象时,PB将激活服务器应用程序以允许对对象进行编辑和修改;在使OLE中的对象称为非活动状态后,可以使用控件属性选项卡来设置控件的属性。
2.2 激活修改window画板中的OLE对象
在OLE控件的弹出菜单中选择open可以激活画板中OLE对象
使用服务器应用程序修改OLE对象
结束修改:使对象恢复为非活动状态,只要单击服务器应用对象之外的任何区域即可,也可以直接关闭服务器应用程序的窗口。
2.3 嵌入和链结OLE控件
可以将OLE对象嵌入或者链结到自己的应用程序中。嵌入对象的数据放在应用程序中,在开发过程中这些数据放在应用程 序的PBl库中,当生成应用后,这些数据将存放在exe或PBd文件中,虽然在程序的运行过程中可以修改,但修改的数据不会保存;链结对象的数据存放在 PB应用程序以外,当链结一个对象时,在PB应用程序中不存放数据文件,而是存放引用数据的指针, 使用链结的数据,对数据的管理和保存都由服务器应用程序负责。这样可以用服务器应用程序修改处理数据,处理后的数据可以保存回原文件中。链结方式应用于需 要多个应用程序共享的数据文件,任何一个应用程序修改了数据文件,都将影响到所有链结该文件的应用程序。
2.4 OLE控件的激活方式
OLE控件的激活方式有offsite和in-place两种激活方式,offsite激活方式是指在PB应用程序 的界面以外单独打开OLE对象,in-place激活方式是指PB应用程序的界面的原位置打开OLE对象。在数据窗口中的dbOLE默认的是 offsite激活方式,而window中的OLE默认的激活方式是in-place。
在PB应用程序中可以用命令
OLE_control.active(offsite) 或者OLE_control.active(in-place)设置OLE对象的以何种方式打开。
2.5 设置和插入OLE对象
在程序运行时可以用函数:
OLE_control.insertfile(soucefile) 插入对象
OLE_control.objectdata = blobvar 设置对象
3、OLE存储
3.1 OLE存储(OLEstorage)的概念
OLE存储(OLEstorage)是OLE数据的一个仓库,存储就象磁盘上的目录结构,它可以是一个OLE对象, 也可以包含在OLE对象中,每个对象都包含在OLE存储或者存储内的子存储内。保存在OLE存储中数据称作OLE流(OLE stream),OLE流同OLE对象的关系就象文件同目录的关系。含有OLE对象的存储或子存储可以看做是属于特殊服务器的信息,在该层次之下的各部分 都可以被相应的服务器程序操作。OLE存储对象是类用户对象,可以说明相应类型的变量,建立与之相应的实例和打开存储等,在使用完存储后需要关闭存储、释 放分配的内存。
3.2 OLE存储的打开和保存
OLE存储可以用open函数打开,open函数的格式为:
Olecontrol.Open(OLEsourcefile),
此函数在OLEsourcefile不存在时,自动创建该文件,所以创建OLE文件也用该函数; OLE存储可以用save函数保存,save函数的格式为:
OLEcontrol.save() // 保存OLE控件
OLEstorage.save() //保存OLE存储
4、处理blob类型数据
对于大二进制数据,在PB Script中是用blob数据类型表示并加以处理。标准SQL语句中的select、insert和update语句无法直接查询blob类型的数据, 在PB中操作blob类型的数据只能用专用的语句,从数据库中查询blob类型的数据的命令是:
selectblob restofselectstatement {using transactionobject};
更新数据库中blob类型数据的格式是:
updateblob tablename
set blobcolumn = blobvarible
restofupatestatement {using transctionobject};
如连接的数据库是sybase或者Sql,则selectblob和updateblob语句要求数据库的自动提 交方式为true,所以在在每次调用selectblob和updateblob语句以前必须用命令 Sqlca.autocommit=true,把数据库的自动提交方式设置为true,在updateblob语句的结束后,再用命令 Sqlca.autocommit = false,把自动提交方式设置为false。 索数据的参数(如flag),然后在可修改列的Protect后的框中输入(user_name是该DataWindow中的一列,代表输入者的名称):
5、数据窗口的blob列
5.1 数据窗口blob列的功能
在PB 的datawindow画板中DBOLE控件允许用户利用这个控件浏览和操作数据库中的大二进制数据,即通过DBOLE控件可以作如下操作:
往数据库中存储大二进制数据,如:excel工作表、word文档、视频文件、图片文件等各种格式的文件;
● 从数据库中检索数据到datawindow对象;
● 使用OLE服务器程序察看修改数据;
● 将修改后的数据保存回数据库;
5.2 在数据窗口中添加blob列的的步骤
1) 选择具有二进制字段的数据表作为数据源建立一新的数据窗口(该窗口可以至少需要包含非数据库表的标识列)
2) 选择insert -control-OLE database blob 菜单,在数据窗口的detail节中要插入blob列的位置单击鼠标,这时将显示如图1所示的对话框
下面解释这些属性的具体含义
1) client class: 客户类名,默认为datawindow
2) client name:客户名,默认为untitled
3) table: 选择含有blob列的数据库表,所选表的字段将出现在右侧的large binary/text column列表框中。
4) large binary/text column:选择一个blob类型的字段列
5) key clause:检索和更新blob数据的关键字表达式其中使用带冒号前缀的变量指出是数据窗口对象的列,如 表达式 id=:id,id是数据库表中的列,变量指出数据窗口对象的列
6) filetemplate :如果需要OLE应用服务器每次打开相同的文件,则在filetemplate框中输入文件名。
7) OLE class :如果不需要OLE应用服务器每次打开相同的文件,则在OLE class框中选择一个OLE类,如Pbrush。
8) Client name expression:显示在OLE服务器应用程序窗口标题的文字,可以输入为:"对应记录的id号是"+id
单击ok按钮关闭对话框,将dbole列添加到适当的位置,保存数据窗口。 预览则可以对数据库中的blob数据进行存取,但是在新建的记录中只能存取OLE class框中选择的一种格式的blob数据,不能存储多种格式的数据;但如果数据库中存有多种格式的数据,可以预览各种格式的数据。
6、源程序建立
1) 首先在数据库中建立如下结构的表blobsave:
字段名称 数据类型 备注
id char(4) primairy key index
s_path char(50)
pic binary (50)
2) 在PB建立PBl库blobsave.PBl
3) 在PBl库blobsave.PBl中建立应用blobsave
在应用的open事件中设置数据库连接程序(本程序中采用的是odbc方式连接数据库,读者可根据自己所建立的数据库的不同选用不同的连接方式,以下连接数据库的代码也有所改动,至于连接不同的数据库的方法,请参考有关资料,本文不做详细介绍):
SQLCA.DBMS = "ODBC"
SQLCA.AutoCommit = False
SQLCA.DBParm = "Connectstring='DSN=blob'"
connect;
open(w_main)
其中命令按钮cb_path的clicked中的代码格式如下:open(w_path)
其中命令按钮cb_dbblob的clicked中的代码格式如下:open(w_dbblob)
其中命令按钮cb_OLEblob的clicked中的代码格式如下:open(w_OLEblob)
4) 建立数据窗口dw_blobsave
按照上文中建立数据窗口的blob列的方法建立数据窗口dw_blobsave如图所示:
其中:add,del,save,cancel,,retrieve等分别为数据窗口dw_blobsave的append row,delete row,update,retrieve动作按钮。
首先创建实例变量 OLEstorage stor1
然后如图建立窗口w_path,其中数据窗口控件dw_1的rowfocuschanged中的代码如下:
long row_num
row_num=dw_1.getrow()
if row_num >0 then
ole_1.insertfile(dw_1.object.s_path[row_num])
end if
其中数据窗口dw_1的buttonclicked中的代码如下:
if dwo.name="cbselect" then
long row_num
row_num=dw_1.getrow()
string filepath,filename
getfileopenname("请选择备注文件",filepath,filename)
dw_1.object.s_path[row_num]=filepath
ole_1.insertfile(filepath)
end if
保存窗口w_path
6) 建立窗口w_dbblob
打开w_path,把其另存为w_dbblob,改变数据窗口dw_1的rowfocuschanged中的代码如下:
blob text1
long row_num
row_num=dw_1.getrow()
if row_num>0 then
string id
id = dw_1.object.id[row_num]
sqlca.autocommit=true
selectblob pic into :text1 from blobsave where id = :id;
ole_1.objectdata=text1
sqlca.autocommit=false
end if
改变数据窗口dw_1的buttonclicked中的代码如下:
long row_num
if dwo.name="cbselect" then
row_num=dw_1.getrow()
string filepath,filename
getfileopenname("请选择备注文件",filepath,filename)
dw_1.object.s_path[row_num]=filepath
ole_1.insertfile(filepath)
end if
if dwo.name="cbsave" then
string id
sqlca.autocommit = true
blob text1
text1 = ole_1.objectdata
dw_1.update()
commit;
row_num=dw_1.getrow()
id=dw_1.object.id[row_num]
updateblob blobsave
set pic = :text1
where id = :id ;
commit;
sqlca.autocommit = FALSE
dw_1.retrieve()
dw_1.scrolltorow(row_num)
end if
保存窗口w_dbblob
7) 建立窗口w_OLEblob
打开w_path,把其另存为w_OLEblob,在窗口w_OLEblob的open事件中写入以下代码:
stor1 = create olestorage
stor1.open("c:\p1.ole") //打开或创建ole文件
在窗口w_OLEblob的close事件中写入以下代码:
destroy stor1
改变数据窗口dw_1的rowfocuschanged中的代码如下:
blob text1
long row_num
row_num=dw_1.getrow()
if row_num>0 then
string id
id = dw_1.object.id[row_num]
ole_1.open(stor1,"w"+id)
end if
改变数据窗口dw_1的buttonclicked中的代码如下:
long row_num
if dwo.name="cbselect" then
row_num=dw_1.getrow()
string filepath,filename
getfileopenname("请选择备注文件",filepath,filename)
dw_1.object.s_path[row_num]=filepath
ole_1.insertfile(filepath)
end if
if dwo.name="cbsave" then
string id
row_num=dw_1.getrow()
id=dw_1.object.id[row_num]
ole_1.saveas(stor1,"w"+id)
stor1.save()
end if
保存窗口w_OLEblob,运行应用程序即可。
7、三种方法的优缺点
方法一:文件保存在固定的路径下,数据库中存取文件路径和名称可以节省数据空间,避免了数据库过分膨胀,但备注 文件必须在一定的目录下,不能丢失,且同一目录下文件不能重名,对文件的管理造成一定的困难,另外,在OLE控件中浏览显示备注文件时,由于每次都要调用 服务器程序,所以速度较慢。
方法二:在数据库中用blob类型或者varbinary类型字段存储备注文件,当文件存储在数据库中以后,就可以删除硬盘上原来的临时文件,不需要复杂的二进制文件管理,且数据库可以存储在网络服务器上,对数据的共享非常方便。
方法三:在本地用OLE存储结构存储备注文件。可以把所有的二进制文件信息存储在一个OLE存储文件中,管理比 较方便。当二进制文件信息存储后,可以删除原来的临时文件;因为打开存储文件后不需要每次执行服务器程序来显示存储信息,所以存取速度较快。 说明:本文在PB6.5,Sql anywhere数据库和PB6.5,Sql Server数据库下,windows98,windows me,NT4.0平台上试验通过。
********************************************************************************************************************
三、 在企业人事管理信息系统设计中,经常要涉及到职工相片的处理问题,如果采用传统的文件名方式存储,不利于数
据的共享。我们在系统中利用sql
server作为工资管理信息系统的后台数据库,利用image数据类型对相片进行存储,前台采用powerbuilder对相片进行处理,很好地实现了
相片数据的存储和共享。
在pb中没有image数据类型,但pb中提供的blob二进制对象,可用于存储大容量数据,例如图像、大文本等,并且在pb中提供了对blob数据
进行特殊处理的sql语句:selectblob和updateblob,可以处理数据库中的image数据类型。具体语法如下:
selectblob 列名into :blob变量 from 表名 where 条件 using 事务对象
updateblob 表名 set 列名:=blob变量 where 条件using 事务对象
如:selectblob photo into:lb_photo from rsdab where bh=′1001′ ;
注意:这两条sql语句每次只能返回一行数据,否则将无效。在处理中我们主要利用了这两条sql语句,用图形控件(picture)来显示相应的相片,使用图片控件的setpicture函数实现。
在具体实现中,人事管理的职工基本情况(人事档案表(rsdab),主要有职工编号、姓名、部门编号及职工其他情况和相片)录入界面如图所示。
程序首先从数据库中取出人事档案表中第一条记录并显示,但相片字段要作特殊处理,因为一般的sql语句不能操作image字段。因此在窗口open事件中写上如下的代码:
blob lb_photo
string ls_bh
//检索数据库中人事档案数据
dw_1.settransobject(sqlca)
dw_1.retrieve()
ls_bh=dw_1.getitemstring(1,″bh″)
//得到当前显示的第一个职工的相片数据并在图片控件中显示
selectblob photo into :lb_photo
from rsdab where bh=:ls_bh
using sqlca;p_1.setpicture(lb_photo)
装入相片按钮的代码如下,主要实现从外部装入相片图形。
integer fh, ret
blob emp_pic,lb_photo
string filename, named,ls_bh,defext = ″bmp″
string filter =″图形文件(*.bmp), *.bmp″
long fsize,ls_row
int num,i//从磁盘选择图形文件
ret = getfileopenname(″选择文件″, filename,named, defext, filter)
//读取文件内容至bolb变量lb_photo中
if ret = 1 then
fsize=filelength(filename)
fh=fileopen(filename, streammode!)
//设置文件读取次数,注意pb中fileread函数
//每次最多能读取32765个字节数据
num=int(fsize/32765)+1
if fh 〈〉 -1 then
for i=1 to num
fileread(fh, emp_pic)
lb_photo=lb_photo+emp_pic
next
fileclose(fh)
end if
end if
//设置图形控制显示图形内容
p_1.setpicture(lb_photo)
//得到当前显示数据的职工编号ls_bh
ls_row=dw_1.getrow()
ls_bh=dw_1.getitemstring(ls_row,″bh″)
//使用updateblob更新数据库中相片列的内容
updateblob rsdab set photo= :lb_photo where bh=:ls_bh using sqlca;
if sqlca.sqlcode〈〉0 then
messagebox(″提示信息″,″保存失败″,exclamation!, ok!, 1)
rollback using sqlca;
//更新失败则回滚事务
else
commit using sqlca;
//更新成功则提交事务
end if
以上是程序的主要代码,界面中其他的按钮对象也要对相片作相应处理,如按钮[下一个]中,需根据职工编号动态改变职工相片的内容,读者可按上述方法自己写出其他事件的代码。
在处理中首先要将职工相片使用扫描仪转换成图形文件或用数码相机拍摄为图形文件,然后利用程序将图形文件读入并存储在数据库中。当然还可以对这个程序
进行改进,如增加对相片的实时扫描处理,增加相片的编辑功能等。还可使用sybase公司的最新产品pb
7.0中的picture控制,该控件支持jpg、gif等格式的图形文件,可以更方便地处理相片。
本程序在sql server 7.0、powerbuilder 6.5中运行通过
************************************************************************************************
PB 中保存图片
//****************************************************************
“
选择”
按钮代码:
lb_image = gf_open_pic(p_1,lb_image)
p_1.setpicture(lb_image)
//***************************************************************
“
清除”
按钮代码:
p_1.picturename = ''''
p_1.picturename = ''''//
(需要两次)
setnull(lb_image)
//***************************************************************
函数gf_open_pic:
//////////////////////////////////////////////////////////////////
//Add by Jeffrey Jiang on 2001.11.13
//
选择图片
/////////////////////////////////////////////////////////////////
//Modfiy by Jeffrey Jiang on 2001.11.15
//
当图片字节大于32765
时,循环读图片
/////////////////////////////////////////////////////////////////
integer li_file,li_ret,loops,i
string ls_file,ls_path
blob lb_small
long flen,bytes_read,new_pos
//search the file
li_ret = getfileopenname("
选择图片文件",ls_path,ls_file, &
"BMP","
图片文件(*.BMP),*.BMP")
if li_ret = 1 then
p_1.picturename = ''''
p_1.picturename = ''''
setnull(lb_image)
if li_file <> -1 then
// Set a wait cursor
setpointer(hourglass!)
flen = filelength(ls_file)
li_file = fileopen(ls_path,streammode!,read!,lockread!)
// Determine how many times to call FileRead
if flen > 32765 then
if mod(flen,32765)=0 then
loops = flen/32765
else
loops = (flen/32765) + 1
end if
else
loops = 1
end if
// Read the file
new_pos = 1
for i = 1 to loops
bytes_read = fileread(li_file,lb_small)
if i = 1 then
lb_image = lb_small
else
lb_image = lb_image + lb_small
end if
next
// close the file
fileclose(li_file)
end if
end if
return lb_image
//***************************************************************
保存按钮代码:
UPDATEBLOB "person" SET "person"."PHOTO" = :lb_image WHERE "person"."C_ID" = :ls_c_id USING SQLCA;
IF sqlcadoor.SQLNRows > 0 THEN
commit using sqlca;
END IF
//***************************************************************
显示图片:
lb_image = f_select_pic(ls_c_id)
p_1.setpicture(lb_image)
//***************************************************************
f_select_pic
函数:
blob lb_image
setnull(lb_image)
selectblob "person"."PHOTO" into:lb_image from "person" where "person"."C_ID"=:ls_c_id using sqlca;
return lb_image
//**************************************************************
//
数据库的字段根据自己的需要更改!!!!!
//*************************************************************
//*****************************************************************************
有人问到,如何清除数据库中的图片而不删除该条记录,操作如下:
保存图片到数据库要用UPDATEBLOB
:
UPDATEBLOB "M" SET "M"."PHOTO" = :ib_image WHERE "M"."C_ID" = :ls_c_id ;
只删除图片而不删除记录要用UPDATE
:
UPDATE "M" SET "M"."PHOTO" = null WHERE "M"."C_ID" = :ls_c_id ;
上一篇: jQuery使用contains过滤器实现精确匹配方法详解_jquery
下一篇: php类型转换