终极解决方案:Crystal report 11以下版本动态显示图片(数据库保存图片路径)

版权声明:欢迎转载,但请注明出处 www.cnblogs.com/alone

环境描述:

  SqlServer 2000、Crystal Report(水晶报表)XI 以下版本

 

引语

  水晶报表以其强大的功能占距了强大的开发市场,其打印出的报表美观、大方,深得用户喜爱,然而其某些功能上不免有些瑕疵。例如,当数据库中只存放了图片的路径时,当你在设计报表时,没有提供将其打印成图片的功能,可能水晶报表公司也看到了广大使用者的需要,在新近的Crystal Report XI中添加了对此的支持,请参见:http://www.businessobjects.com/products/reporting/crystalreports/formatting.aspDynamic image location标题下有详细的Flash功能演示,我就不详细说明了。但Crystal Report XI以下并未提供该功能,用户只能在数据库中使用image字段保存图片、使用第三方的工具或在程序中处理,然而这三种方式都有不足:

 

  1、建立image字段会使数据库文件变得更大,影响了数据库执行效率,而且在特定的情况下,不能使用image字段保存图片,比如用户希望在更新图片时只需将新的图片文件替换掉旧图片时,这个方法就不好用了;

 

  2、使用第三方的工具,参见http://www.crystalkeen.com/tools/cviewimage.htm,以COM组件的方式从数据库中存储的图片路径中提取实际的图片,内嵌于结果集中,提供给Crystal Report。这个方法也有很多不足,比如:不能支持复杂的数据查询;

 

  3、在程序中处理,VB的代码,我没有深入的研究,大概的原理就是循环表中的picture对象,在程序中更改其源位置,这样,在报表生成之前图片就被替换掉了,这种方法当然不用说了,要Coding了,有兴趣的朋友可以研究一下,交流交流。会不会有限制还不清楚,更主要的问题,如果用户只想通过数据库来提供数据源,这个当然不能满足需求了。

  参见:[Crystal Report 8]http://support.businessobjects.com/library/kbase/articles/c2014707.asp

     [Crystal Report 9]http://support.businessobjects.com/communityCS/FilesAndUpdates/cr9_vb_rdc_loadpic.exe.asp

 

  综上所述,Crystal report XI以下版本对图片的支持是开发人员头痛的事,怎样能够才能方便的使Crystal report支持动态根据数据库路径图片显示呢?本人做了以下研究,下面给出一个简单的应用,希望抛砖引玉,有朋友能将其完善。

解决方案

  众所周知,如果数据库中存在一个image字段,在Crystal Report设计报表时使用它是很方便,只需将该字段拖曳到相应的位置,报表在运行时将会从数据库中动态加载图片。如果数据库中并未建立image字段,而是建立了一个字段imgsrc用以保存图片的路径,就不能使用拖曳的方法,怎么解决图片的动态加载呢?通过分析Crystal Report访问image字段和Crystal Report支持从存储过程获取数据源的机制,可以得出以下思路:

 

  编写存储过程,从图片存储的表获取图片的路径,通过使用临时表技术创建一个含image字段的临时表,并使用bcp实用工具加图片导入临时表中,最近通过与临时表关联查询,获得一个包含image字段的数据集。这样,在Crystal Report只需将报表的数据源连接到该存储过程中,在设计时就可直接从该数据集中将image字段拖曳到设计界面了。

  

  下面是实现该存储过程的具体代码,其中的导入图片参考修改了CSDN:邹建 的代码:

 

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_dynaRptImg]'and OBJECTPROPERTY(id, N'IsProcedure'= 1
drop procedure [dbo].[sp_dynaRptImg] 
GO 

create      proc sp_dynaRptImg 
AS 
declare @fname_in     varchar(1000)   --bcp处理应答文件名 
         ,@fsize      varchar(20)     --要处理的文件的大小 
         ,@m_tbname   varchar(50)     --临时表名 
         ,@sql        varchar(8000
         ,@fname      
varchar(1000)   --目录+文件名,处理过程中要使用/覆盖:@filename+_temp 
declare @servename    varchar(30
         ,@username   
varchar(30)  
         ,@password   
varchar(30
     
SET @servename = @@servername 
     
set @username   = 'sa' 
     
set @password ='sa' 
--则取得导入文件的大小 
create table #pic (img image
insert #pic select 0x394872 

create table #pictt(pic varchar(2000),src image
insert into #pictt select 'c:\a.jpg',0x394872 --以下4行为插入演示数据 
insert into #pictt select 'c:\b.jpg',0x394872 
insert into #pictt select 'c:\b.jpg',0x394872 
insert into #pictt select 'c:\b.jpg',0x394872 
insert into #pictt select 'c:\a.jpg',0x394872 

declare cur_1 cursor for select pic from #pictt 
   
open cur_1 
   
fetch cur_1 into @fname 
   
while @@fetch_status = 0 
   
begin 
         
create table #tb(可选名 varchar(20),大小 int 
                   ,创建日期 
varchar(10),创建时间 varchar(20
                   ,上次写操作日期 
varchar(10),上次写操作时间 varchar(20
                   ,上次访问日期 
varchar(10),上次访问时间 varchar(20),特性 int
         
insert into #tb 
         
exec master..xp_getfiledetails @fname 
         
select @fsize=大小 from #tb 
         
drop table #tb 
         
if @fsize is null 
         
begin 
                   
print 'file not found' 
                   
return 
         
end 
         
--生成数据处理应答文件 
         set @m_tbname='[##temp'+cast(newid() as varchar(40))+']' 
         
set @sql='select * into '+@m_tbname+' from( 
                                                     select null as 类型 
                                                     union all select 0 as 前缀 
                                                     union all select 
'+@fsize+' as 长度 
                                                     union all select null as 结束 
                                                     union all select null as 格式 
                                                     ) a
' 

         
exec(@sql) 
         
select @fname_in=@fname+'_temp' 
                    ,@sql
='bcp "'+@m_tbname+'" out "'+@fname_in 
                          
+'" /S"'+@servename 
                          
+case when isnull(@username,'')='' then '' 
                           
else '" /U"'+@username end 
                          
+'" /P"'+isnull(@password,'')+'" /c' 
         
exec master..xp_cmdshell @sql,no_output 
         
--删除临时表 
         set @sql='drop table '+@m_tbname 
         
exec(@sql) 
         
--为数据导入准备临时表 
         set @sql='select top 0 img into ' 
                  
+@m_tbname+' from #pic' 
         
exec(@sql) 
         
--将数据导入到临时表 
         set @sql='bcp "'+@m_tbname+'" in "'+@fname 
                   
+'" /S"'+@servename 
                   
+case when isnull(@username,'')='' then '' 
                            
else '" /U"'+@username end 
                   
+'" /P"'+isnull(@password,''
                   
+'" /i"'+@fname_in+'"' 
         
exec master..xp_cmdshell @sql,no_output 
         
--将数据导入到正式表中 
         set @sql='update #pictt' 
                   
+' set src=b.img' 
                   
+' from #pictt a,' 
                   
+@m_tbname +' b' +' where a.pic =''' + @fname+'''' 
         
exec(@sql) 
         
--删除数据处理临时表 
         set @sql='drop table '+@m_tbname 
         
exec(@sql) 
         
--删除数据处理应答文件 
         set @sql='del '+@fname_in 
         
exec master..xp_cmdshell @sql,no_output 
         
fetch cur_1 into @fname  
    
end 
    
close cur_1 
    
deallocate cur_1 
    
set @sql='select pic,src from #pictt' 
    
exec(@sql) 
    
set @sql='drop table #pic' 
    
exec(@sql) 
    
set @sql='drop table #pictt' 
    
exec(@sql) 

GO 


  上面的存储过程并不完美,如果能将上面的代码做成函数在存储过程中使用就好了。可能在存储过程中筛选出数据到一个临时表,再更改该表的结构,增加一个image字段,通过函数取得图片,同时更新该字段,再者,还可以尽量不使用游标。这样T-SQL的通用性和性能都会有很大的提升。如哪位朋友有兴趣的话,可以贴上来研究一下。

 

posted @ 2005-04-01 14:00  独行者  阅读(4744)  评论(2编辑  收藏  举报